home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / sharewar / slunec / app / httrack.exe / {app} / src / htsback.c < prev    next >
C/C++ Source or Header  |  2002-07-17  |  93KB  |  2,412 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: httrack.c subroutines:                                 */
  34. /*       backing system (multiple socket download)              */
  35. /* Author: Xavier Roche                                         */
  36. /* ------------------------------------------------------------ */
  37.  
  38. #include "htsback.h"
  39.  
  40. /* specific definitions */
  41. #include "htsbase.h"
  42. #include "htsnet.h"
  43. #include "htsthread.h"
  44. #include <stdio.h>
  45. #include <stdlib.h>
  46. #include <string.h>
  47. #include <time.h>
  48. /* END specific definitions */
  49.  
  50. //#if HTS_WIN
  51. #include "htsftp.h"
  52. #if HTS_USEZLIB
  53. #include "htszlib.h"
  54. #endif
  55. //#endif
  56.  
  57. #if HTS_WIN
  58. #ifndef __cplusplus
  59. // DOS
  60. #include <process.h>    /* _beginthread, _endthread */
  61. #endif
  62. #else
  63. #endif
  64.  
  65. #undef test_flush
  66. #define test_flush if (opt->flush) { if (opt->log) { fflush(opt->log); } if (opt->errlog) { fflush(opt->errlog);  } }
  67.  
  68. #define VT_CLREOL       "\33[K"
  69.  
  70.  
  71. // ---
  72. // routines de backing
  73. // retourne l'index d'un lien dans un tableau de backing
  74. int back_index(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  75.   int i=0;
  76.   int index=-1;
  77.   while( i<back_max ) {
  78.     if (back[i].status>=0)    // rΘception OU prΩt
  79.       if (strfield2(back[i].url_adr,adr)) {
  80.         if (strcmp(back[i].url_fil,fil)==0) {
  81.           if (index==-1)    /* first time we meet, store it */
  82.             index=i;
  83.           else if (strcmp(back[i].url_sav,sav)==0) {  /* oops, check sav too */
  84.             index=i;
  85.             return index;
  86.           }
  87.         }
  88.       }
  89.     i++;
  90.   }
  91.   return index;
  92. }
  93.  
  94. // nombre d'entrΘes libres dans le backing
  95. int back_available(lien_back* back,int back_max) {
  96.   int i;
  97.   int nb=0;
  98.   for(i=0;i<back_max;i++)
  99.     if (back[i].status==-1)     /* libre */
  100.       nb++;
  101.   return nb;
  102. }
  103.  
  104. // retourne estimation de la taille des html et fichiers stockΘs en mΘmoire
  105. LLint back_incache(lien_back* back,int back_max) {
  106.   int i;
  107.   LLint sum=0;
  108.   for(i=0;i<back_max;i++)
  109.     if (back[i].status!=-1)
  110.       if (back[i].r.adr)       // ne comptabilier que les blocs en mΘmoire
  111.         sum+=max(back[i].r.size,back[i].r.totalsize);
  112.   return sum;
  113. }
  114.  
  115. // le lien a-t-il ΘtΘ mis en backing?
  116. HTS_INLINE int back_exist(lien_back* back,int back_max,char* adr,char* fil,char* sav) {
  117.   return (back_index(back,back_max,adr,fil,sav)>=0);
  118. }
  119.  
  120. // nombre de sockets en tΓche de fond
  121. int back_nsoc(lien_back* back,int back_max) {
  122.   int n=0;
  123.   int i;
  124.   for(i=0;i<back_max;i++)
  125.     if (back[i].status>0)    // rΘception uniquement
  126.       n++;
  127.  
  128.   return n;
  129. }
  130.  
  131. // objet (lien) tΘlΘchargΘ ou transfΘrΘ depuis le cache
  132. //
  133. // fermer les paramΦtres de transfert,
  134. // et notamment vΘrifier les fichiers compressΘs (dΘcompresser), callback etc.
  135. int back_finalize(httrackp* opt,cache_back* cache,lien_back* back,int p) {
  136.   if (
  137.       (back[p].status == 0)      // ready
  138.       &&
  139.       (!back[p].testmode)        // not test mode
  140.       &&
  141.       (back[p].r.statuscode>0)   // not internal error
  142.       ) {
  143.     char* state="unknown";
  144.    
  145.     /* dΘcompression */
  146. #if HTS_USEZLIB
  147.     if (back[p].r.compressed) {
  148.       if (back[p].r.size > 0) {
  149.         //if ( (back[p].r.adr) && (back[p].r.size>0) ) {
  150.         // stats
  151.         back[p].compressed_size=back[p].r.size;
  152.         // en mΘmoire -> passage sur disque
  153.         if (!back[p].r.is_write) {
  154.           back[p].tmpfile[0]='\0';
  155.           strcpy(back[p].tmpfile,tempnam(NULL,"httrz"));
  156.           if (back[p].tmpfile[0]) {
  157.             back[p].r.out=fopen(back[p].tmpfile,"wb");
  158.             if (back[p].r.out) {
  159.               if ((back[p].r.adr) && (back[p].r.size>0)) {
  160.                 if ((INTsys)fwrite(back[p].r.adr,1,(INTsys)back[p].r.size,back[p].r.out) != back[p].r.size) {
  161.                   back[p].r.statuscode=-1;
  162.                   strcpy(back[p].r.msg,"Write error when decompressing");
  163.                 }
  164.               } else {
  165.                 back[p].tmpfile[0]='\0';
  166.                 back[p].r.statuscode=-1;
  167.                 strcpy(back[p].r.msg,"Empty compressed file");
  168.               }
  169.             } else {
  170.               back[p].tmpfile[0]='\0';
  171.               back[p].r.statuscode=-1;
  172.               strcpy(back[p].r.msg,"Open error when decompressing");
  173.             }
  174.           }
  175.         }
  176.         // fermer fichier sortie
  177.         if (back[p].r.out!=NULL) {
  178.           fclose(back[p].r.out);
  179.           back[p].r.out=NULL;
  180.         }
  181.         // dΘcompression
  182.         if (back[p].tmpfile[0] && back[p].url_sav[0]) {
  183.           LLint size;
  184.           filecreateempty(back[p].url_sav);      // filenote & co
  185.           if ((size = hts_zunpack(back[p].tmpfile,back[p].url_sav))>=0) {
  186.             back[p].r.size=back[p].r.totalsize=size;
  187.             // fichier -> mΘmoire
  188.             if (!back[p].r.is_write) {
  189.               back[p].r.adr=readfile(back[p].url_sav);
  190.               if (!back[p].r.adr) {
  191.                 back[p].r.statuscode=-1;
  192.                 strcpy(back[p].r.msg,"Read error when decompressing");
  193.               }
  194.               remove(back[p].url_sav);
  195.             }
  196.           }
  197.           remove(back[p].tmpfile);
  198.         }
  199.         // stats
  200.         HTS_STAT.total_packed+=back[p].compressed_size;
  201.         HTS_STAT.total_unpacked+=back[p].r.size;
  202.         HTS_STAT.total_packedfiles++;
  203.         // unflag
  204.       }
  205.     }
  206.     back[p].r.compressed=0;
  207. #endif
  208.     
  209.     /* Stats */
  210.     if (cache->txt) {
  211.       char flags[32];
  212.       char s[256];
  213.       time_t tt;
  214.       struct tm* A;
  215.       tt=time(NULL);
  216.       A=localtime(&tt);
  217.       strftime(s,250,"%H:%M:%S",A);
  218.       
  219.       flags[0]='\0';
  220.       /* input flags */
  221.       if (back[p].is_update)
  222.         strcat(flags, "U");   // update request
  223.       else
  224.         strcat(flags, "-");
  225.       if (back[p].range_req_size)
  226.         strcat(flags, "R");   // range request
  227.       else
  228.         strcat(flags, "-");
  229.       /* state flags */
  230.       if (back[p].r.is_file)  // direct to disk
  231.         strcat(flags, "F");
  232.       else
  233.         strcat(flags, "-");
  234.       /* output flags */
  235.       if (!back[p].r.notmodified)
  236.         strcat(flags, "M");   // modified
  237.       else
  238.         strcat(flags, "-");
  239.       if (back[p].r.is_chunk)  // chunked
  240.         strcat(flags, "C");
  241.       else
  242.         strcat(flags, "-");
  243.       if (back[p].r.compressed)
  244.         strcat(flags, "Z");   // gzip
  245.       else
  246.         strcat(flags, "-");
  247.       fprintf(cache->txt,"%s\t"LLintP"/"LLintP"\t%s\t", s, 
  248.         back[p].r.size, back[p].r.totalsize, 
  249.         flags);
  250.     }
  251.     if (back[p].r.statuscode==200) {
  252.       if (back[p].r.size>=0) {
  253.         if (strcmp(back[p].url_fil,"/robots.txt") !=0 ) {
  254.           HTS_STAT.stat_bytes+=back[p].r.size;
  255.           HTS_STAT.stat_files++;
  256.         }
  257.         if ( (!back[p].r.notmodified) && (opt->is_update) ) { 
  258.           HTS_STAT.stat_updated_files++;       // page modifiΘe
  259.           if (opt->log!=NULL) {
  260.             fspc(opt->log,"info");
  261.             if (back[p].is_update) {
  262.               fprintf(opt->log,"engine: transfer-status: link updated: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  263.             } else {
  264.               fprintf(opt->log,"engine: transfer-status: link added: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  265.             }
  266.             test_flush;
  267.           }
  268.           if (cache->txt) {
  269.             if (back[p].is_update) {
  270.               state="updated";
  271.             } else {
  272.               state="added";
  273.             }
  274.           }
  275.         } else {
  276.           if ( (opt->debug>0) && (opt->log!=NULL) ) {
  277.             fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link recorded: %s%s -> %s"LF,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  278.             test_flush;
  279.           }
  280.           if (cache->txt) {
  281.             if (opt->is_update)
  282.               state="untouched";
  283.             else
  284.               state="added";
  285.           }
  286.         }
  287.       } else {
  288.         if ( (opt->debug>0) && (opt->log!=NULL) ) {
  289.           fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: empty file? (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  290.           test_flush;
  291.         }
  292.         if (cache->txt) {
  293.           state="empty";
  294.         }
  295.       }
  296.     } else {
  297.       if ( (opt->debug>0) && (opt->log!=NULL) ) {
  298.         fspc(opt->log,"info"); fprintf(opt->log,"engine: transfer-status: link error (%d, '%s'): %s%s"LF,back[p].r.statuscode,back[p].r.msg,back[p].url_adr,back[p].url_fil);
  299.       }
  300.       if (cache->txt) {
  301.         state="error";
  302.       }
  303.     }
  304.     if (cache->txt) {
  305.       fprintf(cache->txt,
  306.         "%d\t"
  307.         "%s ('%s')\t"
  308.         "%s\t"
  309.         "%s%s\t"
  310.         "%s%s\t%s\t"
  311.         "(from %s%s)"
  312.         LF,
  313.         back[p].r.statuscode,
  314.         state, escape_check_url_addr(back[p].r.msg),
  315.         escape_check_url_addr(back[p].r.contenttype),
  316.         ((back[p].r.etag[0])?"etag:":((back[p].r.lastmodified[0])?"date:":"")), escape_check_url_addr((back[p].r.etag[0])?back[p].r.etag:(back[p].r.lastmodified)),
  317.         escape_check_url_addr(back[p].url_adr),escape_check_url_addr(back[p].url_fil),escape_check_url_addr(back[p].url_sav),
  318.         escape_check_url_addr(back[p].referer_adr),escape_check_url_addr(back[p].referer_fil)
  319.         );
  320.       if (opt->flush)
  321.         fflush(cache->txt);
  322.     }
  323.     
  324.     /* Cache */
  325.     cache_mayadd(opt,cache,&back[p].r,back[p].url_adr,back[p].url_fil,back[p].url_sav);
  326.     
  327.     // status finished callback
  328. #if HTS_ANALYSTE
  329.     hts_htmlcheck_xfrstatus(&back[p]);
  330. #endif
  331.     return 0;
  332.   }
  333.   return -1;
  334. }
  335.  
  336.  
  337. // effacer entrΘe
  338. int back_delete(lien_back* back,int p) {
  339.   if (p>=0) {    // on sait jamais..
  340.     // VΘrificateur d'intΘgritΘ
  341.     #if DEBUG_CHECKINT
  342.     _CHECKINT(&back[p],"Appel back_delete")
  343.     #endif
  344. #if HTS_DEBUG_CLOSESOCK
  345.     char info[256];
  346.     sprintf(info,"back_delete: #%d\n",p);
  347.     DEBUG_W2(info);
  348. #endif
  349.  
  350.     // LibΘrer tous les sockets, handles, buffers..
  351.     if (back[p].r.soc!=INVALID_SOCKET) {
  352. #if HTS_DEBUG_CLOSESOCK
  353.       DEBUG_W("back_delete: deletehttp\n");
  354. #endif
  355.       deletehttp(&back[p].r);
  356.       back[p].r.soc=INVALID_SOCKET;
  357.     }
  358.     
  359. #if HTS_USEOPENSSL
  360.     /* Free OpenSSL structures */
  361.     if (back[p].r.ssl_con) {
  362.       SSL_shutdown(back[p].r.ssl_con);
  363.       SSL_free(back[p].r.ssl_con);
  364.       back[p].r.ssl_con=NULL;
  365.     }
  366.     /*
  367.     if (back[p].r.ssl_soc) {
  368.       BIO_free_all(back[p].r.ssl_soc);
  369.       back[p].r.ssl_soc=NULL;
  370.     }
  371.     */
  372. #endif
  373.     
  374.     if (back[p].r.adr!=NULL) {  // reste un bloc α dΘsallouer
  375.       freet(back[p].r.adr);
  376.       back[p].r.adr=NULL;
  377.     }
  378.     if (back[p].chunk_adr!=NULL) {  // reste un bloc α dΘsallouer
  379.       freet(back[p].chunk_adr);
  380.       back[p].chunk_adr=NULL;
  381.       back[p].chunk_size=0;
  382.       back[p].is_chunk=0;
  383.     }
  384.     // if (back[p].r.is_file) {  // fermer fichier entrΘe
  385.     if (back[p].r.fp!=NULL) {
  386.       fclose(back[p].r.fp);
  387.       back[p].r.fp=NULL;
  388.     }
  389.     // }
  390.  
  391.     /* fichier de sortie */
  392.     if (back[p].r.out!=NULL) {  // fermer fichier sortie
  393.       fclose(back[p].r.out);
  394.       back[p].r.out=NULL;
  395.     }
  396.  
  397.     if (back[p].r.is_write) {     // ecriture directe
  398.       /* Θcrire date "remote" */
  399.       if (strnotempty(back[p].url_sav))          // normalement existe si on a un fichier de sortie
  400.       if (strnotempty(back[p].r.lastmodified))   // last-modified existe
  401.       if (fexist(back[p].url_sav))          // ainsi que le fichier
  402.         set_filetime_rfc822(back[p].url_sav,back[p].r.lastmodified);
  403.  
  404.       /* executer commande utilisateur aprΦs chargement du fichier */
  405.       usercommand(0,NULL,back[p].url_sav);
  406.       back[p].r.is_write=0;
  407.     }
  408.     
  409.     // Tout nettoyer
  410.     memset(&back[p], 0, sizeof(lien_back));  
  411.     back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  412.     
  413.     // Le plus important: libΘrer le champ
  414.     back[p].status=-1;
  415.   }
  416.   return 0;
  417. }
  418.  
  419. /* Space left on backing stack */
  420. int back_stack_available(lien_back* back,int back_max) {
  421.   int p=0,n=0;
  422.   for( ; p < back_max ; p++ )
  423.     if ( back[p].status == -1 )
  424.       n++;
  425.   return n;
  426. }
  427.  
  428. // ajouter un lien en backing
  429. int back_add(lien_back* back,int back_max,httrackp* opt,cache_back* cache,char* adr,char* fil,char* save,char* referer_adr,char* referer_fil,int test,short int* pass2_ptr) {
  430.   int p=0;
  431.  
  432.   // vΘrifier cohΘrence de adr et fil (non vide!)
  433.   if (strnotempty(adr)==0) {
  434.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  435.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: adr is empty for back_add"LF);
  436.     }
  437.     return -1;    // erreur!
  438.   }
  439.   if (strnotempty(fil)==0) {
  440.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  441.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: fil is empty for back_add"LF);
  442.     }
  443.     return -1;    // erreur!
  444.   }
  445.   // FIN vΘrifier cohΘrence de adr et fil (non vide!)
  446.  
  447.   // rechercher emplacement
  448.   while((p<back_max) && back[p].status!=-1) p++;
  449.   if (back[p].status==-1) {    // ok on a de la place
  450.     back[p].send_too[0]='\0';  // Θventuels paramΦtres supplΘmentaires α transmettre au serveur
  451.  
  452.     // ne sert α rien normalement
  453.     if (back[p].r.soc!=INVALID_SOCKET) {
  454. #if HTS_DEBUG_CLOSESOCK
  455.       DEBUG_W("back_add: deletehttp\n");
  456. #endif
  457.       deletehttp(&back[p].r);
  458.     }
  459.  
  460.     // effacer r
  461.     memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  462.  
  463.     // crΘer entrΘe
  464.     strcpy(back[p].url_adr,adr);
  465.     strcpy(back[p].url_fil,fil);
  466.     strcpy(back[p].url_sav,save);
  467.     back[p].pass2_ptr=pass2_ptr;
  468.     // copier referer si besoin
  469.     strcpy(back[p].referer_adr,"");
  470.     strcpy(back[p].referer_fil,"");
  471.     if ((referer_adr) && (referer_fil)) {       // existe
  472.       if ((strnotempty(referer_adr)) && (strnotempty(referer_fil))) {   // non vide
  473.         if (referer_adr[0]!='!') {    // non dΘtruit
  474.           if (strcmp(referer_adr,"file://")) {      // PAS file://
  475.             if (strcmp(referer_adr,"primary")) {      // pas referer 1er lien
  476.               strcpy(back[p].referer_adr,referer_adr);
  477.               strcpy(back[p].referer_fil,referer_fil);
  478.             }
  479.           }
  480.         }
  481.       }
  482.     }
  483.     // sav ne sert α rien pour le moment
  484.     back[p].r.size=0;                   // rien n'a encore ΘtΘ chargΘ
  485.     back[p].r.soc=INVALID_SOCKET;       // pas de socket
  486.     back[p].r.adr=NULL;                 // pas de bloc de mΘmoire
  487.     back[p].r.is_write=0;               // α priori stockage en mΘmoire
  488.     back[p].maxfile_html=opt->maxfile_html;
  489.     back[p].maxfile_nonhtml=opt->maxfile_nonhtml;
  490.     back[p].testmode=test;              // mode test?
  491.     if (!opt->http10)                 // option "forcer 1.0" dΘsactivΘe
  492.       back[p].http11=1;               // autoriser http/1.1
  493.     back[p].head_request=0;
  494.     if (strcmp(back[p].url_sav,BACK_ADD_TEST)==0)    // HEAD
  495.       back[p].head_request=1;
  496.     else if (strcmp(back[p].url_sav,BACK_ADD_TEST2)==0)    // test en GET
  497.       back[p].head_request=2;       // test en get
  498.  
  499.     
  500.     /* Stop requested - abort backing */
  501.     if (opt->state.stop) {
  502.       back[p].r.statuscode=-1;        // fatal
  503.       strcpy(back[p].r.msg,"mirror stopped by user");
  504.       back[p].status=0;  // terminΘ
  505.       if ((opt->debug>0) && (opt->log!=NULL)) {
  506.         fspc(opt->log,"warning"); fprintf(opt->log,"File not added due to mirror cancel: %s%s",adr,fil); test_flush;
  507.       }            
  508.       return 0;
  509.     }
  510.  
  511.  
  512.     // tester cache
  513.     if ((strcmp(adr,"file://"))           /* pas fichier */
  514.       && ( (!test) || (cache->type==1) )   /* cache prioritaire, laisser passer en test! */
  515.       && ( (strnotempty(save)) || (strcmp(fil,"/robots.txt")==0) ) ) {  // si en test on ne doit pas utiliser le cache sinon telescopage avec le 302..
  516.       //if ((!test) && (strcmp(adr,"file://")) 
  517.       //if ((!test) && (strncmp(adr,"ftp://",6)) && (strcmp(adr,"file://")) 
  518. #if HTS_FAST_CACHE
  519.       long int hash_pos;
  520.       int hash_pos_return=0;
  521. #else
  522.       char* a=NULL;
  523. #endif
  524. #if HTS_FAST_CACHE
  525.       if (cache->hashtable) { 
  526. #else
  527.       if (cache->use) { 
  528. #endif
  529.         char buff[HTS_URLMAXSIZE*4];
  530. #if HTS_FAST_CACHE
  531.         strcpy(buff,adr); strcat(buff,fil);
  532.         hash_pos_return=inthash_read((inthash)cache->hashtable,buff,(long int*)&hash_pos);
  533. #else
  534.         buff[0]='\0'; strcat(buff,"\n"); strcat(buff,adr); strcat(buff,"\n"); strcat(buff,fil); strcat(buff,"\n");
  535.         a=strstr(cache->use,buff);
  536. #endif
  537.         
  538.         // Ok, notΘ en cache->. mais bien prΘsent dans le cache ou sur disque?
  539. #if HTS_FAST_CACHE
  540.         if (hash_pos_return) {
  541. #else
  542.         if (a) {
  543. #endif
  544.           if (!test) {      // non mode test
  545. #if HTS_FAST_CACHE
  546.             int pos=hash_pos;
  547. #else
  548.             int pos=-1;
  549.             a+=strlen(buff);
  550.             sscanf(a,"%d",&pos);    // lire position
  551. #endif
  552.             if (pos<0) {    // pas de mise en cache data, vΘrifier existence
  553.               if (fsize(antislash(save)) <= 0) {  // fichier existe pas ou est vide!
  554. #if HTS_FAST_CACHE
  555.                 hash_pos_return=0;
  556. #else
  557.                 a=NULL;    
  558. #endif
  559.                 // dΘvalider car non prΘsent sur disque dans structure originale!!!
  560.                 // sinon, le fichier est ok α priori, mais on renverra un if-modified-since pour
  561.                 // en Ωtre s√r
  562.                 if (opt->norecatch) {              // tester norecatch
  563.                   if (!fexist(antislash(save))) {  // fichier existe pas mais dΘclarΘ: on l'a effacΘ
  564.                     FILE* fp=fopen(antislash(save),"wb");
  565.                     if (fp) fclose(fp);
  566.                     if (opt->log!=NULL) {
  567.                       fspc(opt->log,"warning"); fprintf(opt->log,"File must have been erased by user, ignoring: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  568.                     }
  569.                   }
  570.                 }
  571.               }
  572.             }
  573.           }
  574.         }
  575.         //
  576.       } else
  577. #if HTS_FAST_CACHE
  578.         hash_pos_return=0;
  579. #else
  580.         a=NULL;
  581. #endif
  582.  
  583.       // Existe pas en cache, ou bien pas de cache prΘsent
  584. #if HTS_FAST_CACHE
  585.       if (hash_pos_return) {  // OK existe en cache (et donnΘes aussi)!
  586. #else
  587.       if (a!=NULL) {  // OK existe en cache (et donnΘes aussi)!
  588. #endif
  589.         if (cache->type==1) {   // cache prioritaire (pas de test if-modified..)
  590.                                // dans ce cas on peut Θgalement lire des rΘponses cachΘes comme 404,302... 
  591.           // lire dans le cache
  592.           if (!test)
  593.             back[p].r=cache_read(opt,cache,adr,fil,save);
  594.           else
  595.             back[p].r=cache_read(opt,cache,adr,fil,NULL);       // charger en tΩte uniquement du cache
  596.           if (!back[p].r.location) 
  597.             back[p].r.location=back[p].location_buffer;
  598.           else {    /* recopier */
  599.             strcpy(back[p].location_buffer,back[p].r.location);
  600.             back[p].r.location=back[p].location_buffer;
  601.           }
  602.  
  603.           /* Interdiction taille par le wizard? --> dΘtruire */
  604.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  605.             if (!back_checksize(opt,&back[p],0)) {
  606.               back[p].status=0;  // FINI
  607.               back[p].r.statuscode=-1;
  608.               if (!back[p].testmode)
  609.                 strcpy(back[p].r.msg,"Cached file skipped (too big)");
  610.               else
  611.                 strcpy(back[p].r.msg,"Test: Cached file skipped  (too big)");
  612.               return 0;
  613.             }
  614.           }
  615.  
  616.           if (back[p].r.statuscode != -1) {  // pas d'erreur de lecture
  617.             if ((opt->debug>0) && (opt->log!=NULL)) {
  618.               if (!test) {
  619.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately loaded from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  620.               } else {
  621.                 fspc(opt->log,"debug"); fprintf(opt->log,"File immediately tested from cache: %s%s"LF,back[p].url_adr,back[p].url_fil); test_flush;
  622.               }
  623.             }
  624.             back[p].r.notmodified=1;    // fichier non modifiΘ
  625.             back[p].status=0;  // OK prΩt
  626.  
  627.             // finalize transfer
  628.             if (!test) {
  629.               if (back[p].r.statuscode>0) {
  630.                 back_finalize(opt,cache,back,p);
  631.               }
  632.             }
  633.  
  634.             return 0;
  635.           } else {  // erreur
  636.             // effacer r
  637.             memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  638.             // et continuer (chercher le fichier)
  639.           }
  640.           
  641.         } else if (cache->type==2) {    // si en cache, demander de tester If-Modified-Since
  642.           htsblk* r=cache_header(opt,cache,adr,fil);
  643.  
  644.           /* Interdiction taille par le wizard? */
  645.           {
  646.             LLint save_totalsize=back[p].r.totalsize;
  647.             back[p].r.totalsize=r->totalsize;
  648.             if (!back_checksize(opt,&back[p],1)) {
  649.               r=NULL;
  650.               //
  651.               back[p].status=0;  // FINI
  652.               deletehttp(&back[p].r); back[p].r.soc=INVALID_SOCKET;
  653.               if (!back[p].testmode)
  654.                 strcpy(back[p].r.msg,"File too big");
  655.               else
  656.                 strcpy(back[p].r.msg,"Test: File too big");
  657.               return 0;
  658.             }
  659.             back[p].r.totalsize=save_totalsize;
  660.           }
  661.           
  662.           if (r) {
  663.             if (r->statuscode==200) {     // uniquement des 200 (OK)
  664.               if (strnotempty(r->etag)) {  // ETag (RFC2616)
  665.                 /*
  666.                 - If both an entity tag and a Last-Modified value have been
  667.                 provided by the origin server, SHOULD use both validators in
  668.                 cache-conditional requests. This allows both HTTP/1.0 and
  669.                 HTTP/1.1 caches to respond appropriately.
  670.                 */
  671.                 if (strnotempty(r->lastmodified))
  672.                   sprintf(back[p].send_too,"If-None-Match: %s\r\nIf-Modified-Since: %s\r\n",r->etag,r->lastmodified);
  673.                 else
  674.                   sprintf(back[p].send_too,"If-None-Match: %s\r\n",r->etag);
  675.               }
  676.               else if (strnotempty(r->lastmodified))
  677.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",r->lastmodified);
  678.               else if (strnotempty(cache->lastmodified))
  679.                 sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  680.               
  681.               /* this is an update of a file */
  682.               if (strnotempty(back[p].send_too))
  683.                 back[p].is_update=1;
  684.               back[p].r.req.nocompression=1;   /* Do not compress when updating! */
  685.               
  686.             }
  687.             /* else if (strnotempty(cache->lastmodified))
  688.             sprintf(back[p].send_too,"If-Modified-Since: %s\r\n",cache->lastmodified);
  689.             */
  690.           }
  691. #if DEBUGCA
  692.           printf("..is modified test %s\n",back[p].send_too);
  693. #endif
  694.         } 
  695.         // Okay, pas trouvΘ dans le cache
  696.         // Et si le fichier existe sur disque?
  697.         // Pas dans le cache: fichier n'a pas ΘtΘ transfΘrΘ du tout, donc pas sur disque?
  698.       } else {
  699.         if (fexist(save)) {    // fichier existe? aghl!
  700.           LLint sz=fsize(save);
  701.           // Bon, lα il est possible que le fichier ait ΘtΘ partiellement transfΘrΘ
  702.           // (s'il l'avait ΘtΘ en totalitΘ il aurait ΘtΘ inscrit dans le cache ET existerait sur disque)
  703.           // PAS de If-Modified-Since, on a pas connaissance des donnΘes α la date du cache
  704.           // On demande juste les donnΘes restantes si le date est valide (206), tout sinon (200)
  705.           if ((ishtml(save) != 1) && (ishtml(back[p].url_fil)!=1)) {   // NON HTML (liens changΘs!!)
  706.             if (sz>0) {    // Fichier non vide? (question bΩte, sinon on transfert tout!)
  707.               if (strnotempty(cache->lastmodified)) {     /* pas de If-.. possible */
  708.                 /*if ( (!opt->http10) && (strnotempty(cache->lastmodified)) ) { */    /* ne pas forcer 1.0 */
  709. #if DEBUGCA
  710.                 printf("..if unmodified since %s size "LLintP"\n",cache->lastmodified,(LLint)sz);
  711. #endif
  712.                 if ((opt->debug>1) && (opt->log!=NULL)) {
  713.                   fspc(opt->log,"debug"); fprintf(opt->log,"File partially present ("LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  714.                 }
  715.                 
  716.                 /* impossible - don't have etag or date
  717.                 if (strnotempty(back[p].r.etag)) {  // ETag (RFC2616)
  718.                 sprintf(back[p].send_too,"If-None-Match: %s\r\n",back[p].r.etag);
  719.                 back[p].http11=1;    // En tΩte 1.1
  720.                 } else if (strnotempty(back[p].r.lastmodified)) {
  721.                 sprintf(back[p].send_too,"If-Unmodified-Since: %s\r\n",back[p].r.lastmodified);
  722.                 back[p].http11=1;    // En tΩte 1.1
  723.                 } else 
  724.                 */
  725.                 if (strlen(cache->lastmodified)) {
  726.                   sprintf(back[p].send_too,
  727.                     "If-Unmodified-Since: %s\r\nRange: bytes="LLintP"-\r\n"
  728.                     ,cache->lastmodified,(LLint)sz);
  729.                   back[p].http11=1;    // En tΩte 1.1
  730.                   back[p].range_req_size=sz;
  731.                   back[p].r.req.range_used=1;
  732.                   back[p].r.req.nocompression=1;
  733.                 } else {
  734.                   if ((opt->debug>0) && (opt->errlog!=NULL)) {
  735.                     fspc(opt->log,"warning"); fprintf(opt->log,"Could not find timestamp for partially present file, restarting (lost "LLintP" bytes): %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); test_flush;
  736.                   }
  737.                 }
  738.                 
  739.               } else { 
  740.                 if ((opt->debug>0) && (opt->errlog!=NULL)) {
  741.                   fspc(opt->errlog,"warning");
  742.                   /*
  743.                   if (opt->http10)
  744.                   fprintf(opt->errlog,"File partially present (%d bytes) retransfered due to HTTP/1.0 settings: %s%s"LF,sz,back[p].url_adr,back[p].url_fil);
  745.                   else
  746.                   */
  747.                   fprintf(opt->errlog,"File partially present ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  748.                   test_flush;
  749.                 }
  750.                 /* Sinon requΩte normale... */
  751.                 back[p].http11=0;
  752.               }
  753.             } else if (opt->norecatch) {              // tester norecatch
  754.               filenote(save,NULL);       // ne pas purger tout de mΩme
  755.               back[p].status=0;  // OK prΩt
  756.               back[p].r.statuscode=-1;  // erreur
  757.               strcpy(back[p].r.msg,"Null-size file not recaught");
  758.               return 0;
  759.             }
  760.           } else {
  761.             if ((opt->debug>0) && (opt->errlog!=NULL)) {
  762.               fspc(opt->errlog,"warning");
  763.               fprintf(opt->errlog,"HTML file ("LLintP" bytes) retransfered due to lack of cache: %s%s"LF,(LLint)sz,back[p].url_adr,back[p].url_fil); 
  764.               test_flush;
  765.             }
  766.             /* Sinon requΩte normale... */
  767.             back[p].http11=0;
  768.           }
  769.         }
  770.       }
  771.     }
  772.  
  773.  
  774.     {
  775.       ///htsblk r;   non directement dans la structure-rΘponse!
  776.       T_SOC soc;
  777.       
  778.       // ouvrir liaison, envoyer requΦte
  779.       // ne pas traiter ou recevoir l'en tΩte immΘdiatement
  780.       memset(&(back[p].r), 0, sizeof(htsblk)); back[p].r.soc=INVALID_SOCKET; back[p].r.location=back[p].location_buffer;
  781.       // recopier proxy
  782.       memcpy(&(back[p].r.req.proxy), &opt->proxy, sizeof(opt->proxy));
  783.       // et user-agent
  784.       strcpy(back[p].r.req.user_agent,opt->user_agent);
  785.       strcpy(back[p].r.req.lang_iso,opt->lang_iso);
  786.       back[p].r.req.user_agent_send=opt->user_agent_send;
  787.       // et http11
  788.       back[p].r.req.http11=back[p].http11;
  789.       back[p].r.req.nocompression=opt->nocompression;
  790.  
  791.       // mode ftp, court-circuit!
  792.       if (strfield(back[p].url_adr,"ftp://")) {
  793.         if (back[p].testmode) {
  794.           if ((opt->debug>1) && (opt->errlog!=NULL)) {
  795.             fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: forbidden test with ftp link for back_add"LF);
  796.           }
  797.           return -1;    // erreur pas de test permis
  798.         }
  799.         if (!(back[p].r.req.proxy.active && opt->ftp_proxy)) { // connexion directe, gΘrΘe en thread
  800.           back[p].status=1000;   // connexion ftp
  801. #if USE_BEGINTHREAD
  802.           launch_ftp(&(back[p]));
  803. #else
  804.           {
  805.             char nid[32];
  806.             sprintf(nid,"htsftp%d-in_progress.lock",p);
  807.             strcpy(back[p].location_buffer,fconcat(opt->path_log,nid));
  808.           }
  809.           launch_ftp(&(back[p]),back[p].location_buffer,opt->exec);
  810. #endif
  811.           return 0;
  812.         }
  813.       }
  814. #if HTS_USEOPENSSL
  815.       else if (strfield(back[p].url_adr,"https://")) {        // let's rock
  816.         back[p].r.ssl = 1;
  817.         // back[p].r.ssl_soc = NULL;
  818.         back[p].r.ssl_con = NULL;
  819.       }
  820. #endif
  821.       
  822. #if HTS_XGETHOST
  823. #if HDEBUG
  824.       printf("back_solve..\n");
  825. #endif
  826.       back[p].status=101;    // tentative de rΘsolution du nom de host
  827.       soc=INVALID_SOCKET;    // pas encore ouverte
  828.       back_solve(&back[p]);  // prΘparer
  829.       if (host_wait(&back[p])) {  // prΩt, par ex fichier ou dispo dans dns
  830. #if HDEBUG
  831.       printf("ok, dns cache ready..\n");
  832. #endif
  833.         soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  834.         if (soc==INVALID_SOCKET) {
  835.           back[p].status=0;  // fini, erreur
  836.         }
  837.       }
  838. //
  839. #else
  840. //
  841. #if CNXDEBUG
  842.       printf("XFopen..\n");
  843. #endif
  844.  
  845.       if (strnotempty(back[p].send_too))    // envoyer un if-modified-since
  846. #if HTS_XCONN
  847.       soc=http_xfopen(0,0,0,back[p].send_too,adr,fil,&(back[p].r));
  848. #else
  849.       soc=http_xfopen(0,0,1,back[p].send_too,adr,fil,&(back[p].r));
  850. #endif
  851.       else
  852. #if HTS_XCONN
  853.         soc=http_xfopen(test,0,0,NULL,adr,fil,&(back[p].r));
  854. #else
  855.       soc=http_xfopen(test,0,1,NULL,adr,fil,&(back[p].r));
  856. #endif
  857. #endif
  858.       if (opt->timeout>0) {    // gestion du opt->timeout
  859.         back[p].timeout=opt->timeout;
  860.         back[p].timeout_refresh=time_local();
  861.       } else {
  862.         back[p].timeout=-1;    // pas de gestion (default)
  863.       }
  864.       
  865.       if (opt->rateout>0) {    // gestion d'un taux minimum de transfert tolΘrΘ
  866.         back[p].rateout=opt->rateout;
  867.         back[p].rateout_time=time_local();
  868.       } else {
  869.         back[p].rateout=-1;    // pas de gestion (default)
  870.       }
  871.  
  872.       // Note: on charge les code-page erreurs (erreur 404, etc) dans le cas o∙ cela est
  873.       // rattrapable (exemple: 301,302 moved xxx -> refresh sur la page!)
  874.       //if ((back[p].statuscode!=200) || (soc<0)) { // ERREUR HTTP/autre
  875.  
  876. #if CNXDEBUG
  877. printf("Xfopen ok, poll..\n");
  878. #endif
  879.  
  880. #if HTS_XGETHOST
  881.     if (soc!=INVALID_SOCKET)
  882.       if (back[p].status==101) {  // pas d'erreur
  883.         if (!back[p].r.is_file)
  884.           back[p].status=100;   // connexion en cours
  885.         else
  886.           back[p].status=1;     // fichier
  887.       }
  888.  
  889. #else
  890.       if (soc==INVALID_SOCKET) { // erreur socket
  891.         back[p].status=0;    // FINI
  892.         //if (back[p].soc!=INVALID_SOCKET) deletehttp(back[p].soc);
  893.         back[p].r.soc=INVALID_SOCKET;
  894.       } else {
  895.         if (!back[p].r.is_file)
  896. #if HTS_XCONN
  897.           back[p].status=100;   // connexion en cours
  898. #else
  899.           back[p].status=99;    // chargement en tΩte en cours
  900. #endif
  901.         else
  902.           back[p].status=1;     // chargement fichier
  903. #if BDEBUG==1
  904.         printf("..loading header\n");
  905. #endif
  906.       }
  907. #endif
  908.       
  909.     }
  910.  
  911.  
  912.     // note: si il y a erreur (404,etc) status=2 (terminΘ/Θchec) mais
  913.     // le lien est considΘrΘ comme traitΘ
  914.     //if (back[p].soc<0)  // erreur
  915.     //  return -1;
  916.  
  917.     return 0;
  918.   } else {
  919.     if ((opt->debug>1) && (opt->errlog!=NULL)) {
  920.       fspc(opt->errlog,"debug"); fprintf(opt->errlog,"error: no space left in stack for back_add"LF);
  921.     }
  922.     return -1;    // plus de place
  923.   }
  924. }
  925.  
  926.  
  927.  
  928. #if HTS_XGETHOST
  929. #if USE_BEGINTHREAD
  930. // lancement multithread du robot
  931. PTHREAD_TYPE Hostlookup(void* iadr_p) {
  932.   char iadr[256];
  933.   t_dnscache* cache=_hts_cache();  // adresse du cache
  934.   t_hostent* hp;
  935.   int error_found=0;
  936.  
  937.   // recopier (aprΦs id:pass)
  938. #if DEBUGDNS 
  939.   printf("resolv in background: %s\n",jump_identification(iadr_p));
  940. #endif
  941.   strcpy(iadr,jump_identification(iadr_p));
  942.   // couper Θventuel :
  943.   {
  944.     char *a;
  945.     if ( (a=jump_toport(iadr)) )
  946.       *a='\0';          // get rid of it
  947.   }
  948.   freet(iadr_p);
  949.  
  950.   // attendre que le cache dns soit prΩt
  951.   while(_hts_lockdns(-1));  // attendre libΘration
  952.   _hts_lockdns(1);          // locker
  953.   while(cache->n) {
  954.     if (strcmp(cache->iadr,iadr)==0) {
  955.       error_found=1;
  956.     }
  957.     cache=cache->n;    // calculer queue
  958.   }
  959.   if (strcmp(cache->iadr,iadr)==0) {
  960.     error_found=1;
  961.   }
  962.  
  963.   if (!error_found) {
  964.     // en gros copie de hts_gethostbyname sans le return
  965.     cache->n=(t_dnscache*) calloct(1,sizeof(t_dnscache));
  966.     if (cache->n!=NULL) {
  967.       t_fullhostent fullhostent_buffer;
  968.       strcpy(cache->n->iadr,iadr);
  969.       cache->n->host_length=0;        /* pour le moment rien */
  970.       cache->n->n=NULL;
  971.       _hts_lockdns(0);          // dΘlocker
  972.       
  973.       /* resolve */
  974. #if DEBUGDNS 
  975.       printf("gethostbyname() in progress for %s\n",iadr);
  976. #endif
  977.       cache->n->host_length=-1;
  978.       memset(cache->n->host_addr, 0, sizeof(cache->n->host_addr));
  979.       hp=vxgethostbyname(iadr, &fullhostent_buffer);
  980.       if (hp!=NULL) {
  981.         memcpy(cache->n->host_addr, hp->h_addr, hp->h_length);
  982.         cache->n->host_length = hp->h_length;
  983.       }
  984.     } else 
  985.     _hts_lockdns(0);          // dΘlocker
  986.   } else {
  987. #if DEBUGDNS 
  988.     printf("aborting resolv for %s (found)\n",iadr);
  989. #endif
  990.     _hts_lockdns(0);          // dΘlocker
  991.   }
  992.   // fin de copie de hts_gethostbyname
  993.  
  994. #if DEBUGDNS 
  995.   printf("quitting resolv for %s (result: %d)\n",iadr,(cache->n!=NULL)?cache->n->host_length:(-999));
  996. #endif
  997.  
  998.   return PTHREAD_RETURN;     /* _endthread implied  */
  999. }
  1000. #endif
  1001.  
  1002. // attendre que le host (ou celui du proxy) ait ΘtΘ rΘsolu
  1003. // si c'est un fichier, la rΘsolution est immΘdiate
  1004. // idem pour ftp://
  1005. void back_solve(lien_back* back) {
  1006.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1007.   //## if (back->url_adr[0]!=lOCAL_CHAR) {  // qq chose α prΘparer
  1008.     char* a;
  1009.     if (!(back->r.req.proxy.active))
  1010.       a=back->url_adr;
  1011.     else
  1012.       a=back->r.req.proxy.name;
  1013.     a = jump_protocol(a);
  1014.     if (!hts_dnstest(a)) {   // non encore testΘ!..
  1015.       // inscire en thread
  1016. #if HTS_WIN
  1017.       // Windows
  1018. #if USE_BEGINTHREAD
  1019.       {
  1020.         char* p = calloct(strlen(a)+2,1);
  1021.         if (p) {
  1022.           strcpy(p,a);
  1023.           _beginthread( Hostlookup , 0, p );
  1024.         }
  1025.       }
  1026. #else
  1027.       /*t_hostent* h=*/
  1028.       /*hts_gethostbyname(a);*/  // calcul
  1029. #endif
  1030. #else
  1031. #if USE_BEGINTHREAD
  1032.         char* p = calloct(strlen(a)+2,1);
  1033.         if (p) {
  1034.           strcpy(p,a);
  1035.           _beginthread( Hostlookup , 0, p );
  1036.         }
  1037. #else
  1038.       // Sous Unix, le gethostbyname() est bloquant..
  1039.       /*t_hostent* h=*/
  1040.       /*hts_gethostbyname(a);*/  // calcul
  1041. #endif
  1042. #endif
  1043.     }
  1044.   }
  1045. }
  1046.  
  1047. // dΘtermine si le host a pu Ωtre rΘsolu
  1048. int host_wait(lien_back* back) {
  1049.   if ((!strfield(back->url_adr,"file://")) && (!strfield(back->url_adr,"ftp://"))) {
  1050.   //## if (back->url_adr[0]!=lOCAL_CHAR) {
  1051.     if (!(back->r.req.proxy.active)) {
  1052.       return (hts_dnstest(back->url_adr));
  1053.     } else {
  1054.       return (hts_dnstest(back->r.req.proxy.name));      
  1055.     }
  1056.   } else return 1;    // prΩt, fichier local
  1057. }
  1058. #endif
  1059.  
  1060.  
  1061. // Θlimine les fichiers non html en backing (anticipation)
  1062. // cleanup non-html files in backing to save backing space
  1063. // and allow faster "save in cache" operation
  1064. void back_clean(httrackp* opt,cache_back* cache,lien_back* back,int back_max) {
  1065.   int i;
  1066.   for(i=0;i<back_max;i++) {
  1067.     if (back[i].status == 0) {                                   // ready
  1068.       if (!back[i].testmode) {                                   // not test mode
  1069.         if (strnotempty(back[i].url_sav)) {                      // filename exists
  1070.           if (back[i].r.is_write) {                              // not in memory (on disk, ready)
  1071.             if (back[i].r.size>0) {                              // size>0
  1072.               if (back[i].r.statuscode==200) {                   // HTTP "OK"
  1073.                 if (!is_hypertext_mime(back[i].r.contenttype)) { // not HTML/hypertext
  1074.                   if (!may_be_hypertext_mime(back[i].r.contenttype)) { // may NOT be parseable mime type
  1075.                     if (back[i].pass2_ptr) {
  1076.                       // finalize
  1077.                       // // back_finalize(opt,cache,back,i);
  1078.                       // stats
  1079.                       //HTS_STAT.stat_bytes+=back[i].r.size;
  1080.                       //HTS_STAT.stat_files++;
  1081.                       //if ( (!back[i].r.notmodified) && (opt->is_update) ) { 
  1082.                       //  HTS_STAT.stat_updated_files++;       // page modifiΘe
  1083.                       //}
  1084.                       //cache_mayadd(opt,cache,&back[i].r,back[i].url_adr,back[i].url_fil,back[i].url_sav);
  1085.                       *back[i].pass2_ptr=-1;  // Done!
  1086.                       back_delete(back,i);    // Delete backing entry
  1087.                       if ((opt->debug>0) && (opt->log!=NULL)) {
  1088.                         fspc(opt->log,"info"); fprintf(opt->log,"File successfully written in background: %s"LF,back[i].url_sav); test_flush;
  1089.                       }
  1090.                     }
  1091.                   }
  1092.                 }
  1093.               }
  1094.             }
  1095.           }
  1096.         }
  1097.       }
  1098.     }
  1099.   }            
  1100. }
  1101.  
  1102.  
  1103. // attente (gestion des buffers des sockets)
  1104. void back_wait(lien_back* back,int back_max,httrackp* opt,cache_back* cache,TStamp stat_timestart) {
  1105.   int i;
  1106.   T_SOC nfds=INVALID_SOCKET;
  1107.   fd_set fds,fds_c,fds_e;     // fds pour lecture, connect (write), et erreur
  1108.   int nsockets;     // nbre sockets
  1109.   LLint max_read_bytes;  // max bytes read per sockets
  1110.   struct timeval tv;
  1111.   int do_wait=0;
  1112.   int gestion_timeout=0;
  1113.   int busy_recv=0;     // pas de donnΘes pour le moment   
  1114.   int busy_state=0;    // pas de connexions
  1115.   int max_loop;  // nombre de boucles max α parcourir..
  1116. #if HTS_ANALYSTE
  1117.   int max_loop_chk=0;
  1118. #endif
  1119.  
  1120.  
  1121.   // max. number of loops
  1122.   max_loop=8;
  1123.  
  1124. #if 1
  1125.   // Cleanup the stack to save space!
  1126.   back_clean(opt,cache,back,back_max);
  1127. #endif
  1128.  
  1129.   // recevoir tant qu'il y a des donnΘes (avec un maximum de max_loop boucles)
  1130.   do_wait=0;
  1131.   gestion_timeout=0;
  1132.   do {
  1133.     int max_c;
  1134.     busy_state=busy_recv=0;
  1135.  
  1136. #if 0
  1137.     check_rate(stat_timestart,opt->maxrate);    // vΘrifier taux de transfert
  1138. #endif
  1139.     // inscrire les sockets actuelles, et rechercher l'ID la plus ΘlevΘe
  1140.     FD_ZERO(&fds);
  1141.     FD_ZERO(&fds_c);
  1142.     FD_ZERO(&fds_e);
  1143.     nsockets=0;
  1144.     max_read_bytes=TAILLE_BUFFER;     // maximum bytes that can be read
  1145.     nfds=INVALID_SOCKET;
  1146.  
  1147.     max_c=1;
  1148.     for(i=0;i<back_max;i++) {
  1149.  
  1150.       // en cas de gestion du connect prΘemptif
  1151. #if HTS_XCONN
  1152.       if (back[i].status==100) {      // connexion
  1153.         do_wait=1;
  1154.  
  1155.         // noter socket write
  1156.         FD_SET(back[i].r.soc,&fds_c);
  1157.         
  1158.         // noter socket erreur
  1159.         FD_SET(back[i].r.soc,&fds_e);
  1160.  
  1161.         // calculer max
  1162.         if (max_c) {
  1163.           max_c=0;
  1164.           nfds=back[i].r.soc;
  1165.         } else if (back[i].r.soc>nfds) {
  1166.           // ID socket la plus ΘlevΘe
  1167.           nfds=back[i].r.soc;
  1168.         }
  1169.         
  1170.       } else
  1171. #endif
  1172. #if HTS_XGETHOST
  1173.       if (back[i].status==101) {      // attente
  1174.         // rien α faire..
  1175.       } else
  1176. #endif
  1177.       // poll pour la lecture sur les sockets
  1178.       if ((back[i].status>0) && (back[i].status<100)) {  // en rΘception http
  1179.             
  1180. #if BDEBUG==1
  1181.         //printf("....socket in progress: %d\n",back[i].r.soc);
  1182. #endif
  1183.         // non local et non ftp
  1184.         if (!back[i].r.is_file) {
  1185.         //## if (back[i].url_adr[0]!=lOCAL_CHAR) {
  1186.           
  1187.           // vΘrification de sΘcuritΘ
  1188.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1189.             do_wait=1;
  1190.             
  1191.             // noter socket read
  1192.             FD_SET(back[i].r.soc,&fds);
  1193.             
  1194.             // noter socket error
  1195.             FD_SET(back[i].r.soc,&fds_e);
  1196.             
  1197.             // incrΘmenter nombre de sockets
  1198.             nsockets++;
  1199.  
  1200.             // calculer max
  1201.             if (max_c) {
  1202.               max_c=0;
  1203.               nfds=back[i].r.soc;
  1204.             } else if (back[i].r.soc>nfds) {
  1205.               // ID socket la plus ΘlevΘe
  1206.               nfds=back[i].r.soc;
  1207.             }
  1208.           } else {
  1209.             back[i].r.statuscode=-4;
  1210.             if (back[i].status==100)
  1211.               strcpy(back[i].r.msg,"Connect Error");
  1212.             else
  1213.               strcpy(back[i].r.msg,"Receive Error");
  1214.             back[i].status=0;  // terminΘ
  1215.             if ((opt->debug>0) && (opt->log!=NULL)) {
  1216.               fspc(opt->log,"warning"); fprintf(opt->log,"Unexpected socket error during pre-loop"LF); test_flush;
  1217.             }            
  1218.           }
  1219. #if WIDE_DEBUG
  1220.           else {
  1221.             DEBUG_W("PANIC!!! Socket is invalid in a poll test!\n");
  1222.           }
  1223. #endif
  1224.           
  1225.         }
  1226.         
  1227.       }
  1228.     }    
  1229.     nfds++;
  1230.     
  1231.     if (do_wait) {  // attendre
  1232.       // temps d'attente max: 2.5 seconde
  1233.       tv.tv_sec=HTS_SOCK_SEC;
  1234.       tv.tv_usec=HTS_SOCK_MS;
  1235.       
  1236. #if BDEBUG==1
  1237.       printf("..select\n");
  1238. #endif
  1239.       
  1240.       // poller les sockets-attention au noyau sous Unix..
  1241. #if HTS_WIDE_DEBUG    
  1242.       DEBUG_W("select\n");
  1243. #endif
  1244.       select(nfds,&fds,&fds_c,&fds_e,&tv);
  1245. #if HTS_WIDE_DEBUG    
  1246.       DEBUG_W("select done\n");
  1247. #endif      
  1248.     }
  1249.     
  1250.     // maximum data which can be received for a socket, if limited
  1251.     if (nsockets) {
  1252.       if (opt->maxrate>0) {
  1253.         max_read_bytes = ( check_downloadable_bytes(opt->maxrate) / nsockets );
  1254.       }
  1255.     }
  1256.     if (!max_read_bytes)
  1257.       busy_recv=0;
  1258.     
  1259.     // recevoir les donnΘes arrivΘes
  1260.     for(i=0;i<back_max;i++) {
  1261.       
  1262.       if (back[i].status>0) {
  1263.         if (!back[i].r.is_file) {  // not file..
  1264.           if (back[i].r.soc!=INVALID_SOCKET) {  // hey, you never know..
  1265.             int err=FD_ISSET(back[i].r.soc,&fds_e);
  1266.             if (err) {
  1267.               if (back[i].r.soc!=INVALID_SOCKET) {
  1268. #if HTS_DEBUG_CLOSESOCK
  1269.                 DEBUG_W("back_wait: deletehttp\n");
  1270. #endif
  1271.                 deletehttp(&back[i].r);
  1272.               }
  1273.               back[i].r.soc=INVALID_SOCKET;
  1274.               back[i].r.statuscode=-4;
  1275.               if (back[i].status==100)
  1276.                 strcpy(back[i].r.msg,"Connect Error");
  1277.               else
  1278.                 strcpy(back[i].r.msg,"Receive Error");
  1279.               back[i].status=0;  // terminΘ
  1280.             }
  1281.           }
  1282.         }
  1283.       }
  1284.       
  1285.       // ---- FLAG WRITE MIS A UN?: POUR LE CONNECT
  1286.       if (back[i].status==100) {   // attendre connect
  1287.         int dispo=0;
  1288.         // vΘrifier l'existance de timeout-check
  1289.         if (!gestion_timeout)
  1290.           if (back[i].timeout>0)
  1291.             gestion_timeout=1;
  1292.           
  1293.           // connectΘ?
  1294.           dispo=FD_ISSET(back[i].r.soc,&fds_c);
  1295.           if (dispo) {    // ok connected!!
  1296.             busy_state=1;
  1297.             
  1298. #if HTS_USEOPENSSL
  1299.             /* SSL mode */
  1300.             if (back[i].r.ssl) {
  1301.               // handshake not yet launched
  1302.               if (!back[i].r.ssl_con) {
  1303.                 SSL_CTX_set_options(openssl_ctx, SSL_OP_ALL);
  1304.                 // new session
  1305.                 back[i].r.ssl_con = SSL_new(openssl_ctx);
  1306.                 if (back[i].r.ssl_con) {
  1307.                   SSL_clear(back[i].r.ssl_con);
  1308.                   if (SSL_set_fd(back[i].r.ssl_con, back[i].r.soc) == 1) {
  1309.                     SSL_set_connect_state(back[i].r.ssl_con);
  1310.                     back[i].status = 102;         /* handshake wait */
  1311.                   } else
  1312.                     back[i].r.statuscode=-6;
  1313.                 } else
  1314.                   back[i].r.statuscode=-6;
  1315.               }
  1316.               /* Error */
  1317.               if (back[i].r.statuscode == -6) {
  1318.                 strcpy(back[i].r.msg, "bad SSL/TLS handshake");
  1319.                 deletehttp(&back[i].r);
  1320.                 back[i].r.soc=INVALID_SOCKET;
  1321.                 back[i].r.statuscode=-5;
  1322.                 back[i].status=0;
  1323.               }
  1324.             }
  1325.             
  1326. #endif
  1327.  
  1328. #if BDEBUG==1
  1329.           printf("..connect ok on socket %d\n",back[i].r.soc);
  1330. #endif
  1331.           
  1332.           if ((back[i].r.soc != INVALID_SOCKET) && (back[i].status==100)) {
  1333.             /* limit nb. connections/seconds to avoid server overload */
  1334.             if (opt->maxconn>0) {
  1335.               Sleep(1000/opt->maxconn);
  1336.             }
  1337.             
  1338.             if (back[i].timeout>0) {    // refresh timeout si besoin est
  1339.               back[i].timeout_refresh=time_local();
  1340.             }
  1341.             if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1342.               back[i].rateout_time=time_local();
  1343.             }
  1344.             // envoyer header
  1345.             //if (strcmp(back[i].url_sav,BACK_ADD_TEST)!=0)    // vrai get
  1346.             if (!back[i].head_request)
  1347.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1348.             else if (back[i].head_request==2)  // test en GET!
  1349.               http_sendhead(opt->cookie,0,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1350.             else        // test!
  1351.               http_sendhead(opt->cookie,1,back[i].send_too,back[i].url_adr,back[i].url_fil,back[i].referer_adr,back[i].referer_fil,&back[i].r);         
  1352.             back[i].status=99;  // attendre en tΩte maintenant
  1353.           }
  1354.         }
  1355.         
  1356.         // attente gethostbyname
  1357.       }
  1358. #if HTS_USEOPENSSL
  1359.       else if (back[i].status==102) {   // wait for SSL handshake
  1360.         /* SSL mode */
  1361.         if (back[i].r.ssl) {
  1362.           int conn_code;
  1363.           if ((conn_code = SSL_connect(back[i].r.ssl_con)) <= 0) {
  1364.             /* non blocking I/O, will retry */
  1365.             int err_code = SSL_get_error(back[i].r.ssl_con, conn_code);
  1366.             if (
  1367.               (err_code != SSL_ERROR_WANT_READ)
  1368.               &&
  1369.               (err_code != SSL_ERROR_WANT_WRITE)
  1370.               ) {
  1371.               char tmp[256];
  1372.               tmp[0]='\0';
  1373.               ERR_error_string(err_code, tmp);
  1374.               back[i].r.msg[0]='\0';
  1375.               strncat(back[i].r.msg, tmp, sizeof(back[i].r.msg) - 2);
  1376.               if (!strnotempty(back[i].r.msg)) {
  1377.                 sprintf(back[i].r.msg, "SSL/TLS error %d", err_code);
  1378.               }
  1379.               deletehttp(&back[i].r);
  1380.               back[i].r.soc=INVALID_SOCKET;
  1381.               back[i].r.statuscode=-5;
  1382.               back[i].status=0;
  1383.             }
  1384.           } else {        /* got it! */
  1385.             back[i].status=100;       // back to waitconnect
  1386.           }
  1387.         } else {
  1388.           strcpy(back[i].r.msg, "unexpected SSL/TLS error");
  1389.           deletehttp(&back[i].r);
  1390.           back[i].r.soc=INVALID_SOCKET;
  1391.           back[i].r.statuscode=-5;
  1392.           back[i].status=0;
  1393.         }
  1394.         
  1395.       }
  1396. #endif
  1397. #if HTS_XGETHOST
  1398.       else if (back[i].status==101) {  // attendre gethostbyname
  1399. #if DEBUGDNS 
  1400.         //printf("status 101 for %s\n",back[i].url_adr);
  1401. #endif
  1402.  
  1403.         if (!gestion_timeout)
  1404.           if (back[i].timeout>0)
  1405.             gestion_timeout=1;
  1406.  
  1407.         if (host_wait(&back[i])) {    // prΩt
  1408.           back[i].status=100;        // attente connexion
  1409.           if (back[i].timeout>0) {    // refresh timeout si besoin est
  1410.             back[i].timeout_refresh=time_local();
  1411.           }
  1412.           if (back[i].rateout>0) {    // le taux de transfert de base sur le dΘbut de la connexion
  1413.             back[i].rateout_time=time_local();
  1414.           }
  1415.  
  1416.           back[i].r.soc=http_xfopen(0,0,0,back[i].send_too,back[i].url_adr,back[i].url_fil,&(back[i].r));
  1417.           if (back[i].r.soc==INVALID_SOCKET) {
  1418.             back[i].status=0;  // fini, erreur
  1419.             if (back[i].r.soc!=INVALID_SOCKET) {
  1420. #if HTS_DEBUG_CLOSESOCK
  1421.               DEBUG_W("back_wait(2): deletehttp\n");
  1422. #endif
  1423.               deletehttp(&back[i].r);
  1424.             }
  1425.             back[i].r.soc=INVALID_SOCKET;
  1426.             back[i].r.statuscode=-5;
  1427.             if (strnotempty(back[i].r.msg)==0) 
  1428.               strcpy(back[i].r.msg,"Unable to resolve host name");
  1429.           }
  1430.         }
  1431.         
  1432.  
  1433.       // ---- FLAG READ MIS A UN?: POUR LA RECEPTION
  1434.       }
  1435. #endif
  1436. #if USE_BEGINTHREAD
  1437.       // ..rien α faire, c'est magic les threads
  1438. #else
  1439.       else if (back[i].status==1000) {  // en rΘception ftp
  1440.         if (!fexist(back[i].location_buffer)) {    // terminΘ
  1441.           FILE* fp;
  1442.           fp=fopen(fconcat(back[i].location_buffer,".ok"),"rb");
  1443.           if (fp) {
  1444.             int j=0;
  1445.             fscanf(fp,"%d ",&(back[i].r.statuscode));
  1446.             while(!feof(fp)) {
  1447.               int c = fgetc(fp);
  1448.               if (c!=EOF)
  1449.                 back[i].r.msg[j++]=c;
  1450.             }
  1451.             back[i].r.msg[j++]='\0';
  1452.             fclose(fp);
  1453.             remove(fconcat(back[i].location_buffer,".ok"));
  1454.             strcpy(fconcat(back[i].location_buffer,".ok"),"");
  1455.           } else {
  1456.             strcpy(back[i].r.msg,"Unknown ftp result, check if file is ok");
  1457.             back[i].r.statuscode=-1;
  1458.           }
  1459.           back[i].status=0;
  1460.           // finalize transfer
  1461.           if (back[i].r.statuscode>0) {
  1462.             back_finalize(opt,cache,back,i);
  1463.           }
  1464.         }
  1465.       }
  1466. #endif
  1467.       else if ((back[i].status>0) && (back[i].status<1000)) {  // en rΘception http
  1468.         int dispo=0;
  1469.         
  1470.         // vΘrifier l'existance de timeout-check
  1471.         if (!gestion_timeout)
  1472.           if (back[i].timeout>0)
  1473.             gestion_timeout=1;
  1474.           
  1475.           // donnΘes dispo?
  1476.           //## if (back[i].url_adr[0]!=lOCAL_CHAR)
  1477.           if (!back[i].r.is_file) {
  1478.             dispo=FD_ISSET(back[i].r.soc,&fds);
  1479.           }
  1480.           else
  1481.             dispo=1;
  1482.  
  1483.           // Check transfer rate!
  1484.           if (!max_read_bytes)
  1485.             dispo=0;                // limit transfer rate
  1486.           
  1487.           if (dispo) {    // donnΘes dispo
  1488.             LLint retour_fread;
  1489.             busy_recv=1;    // on rΘcupΦre encore
  1490. #if BDEBUG==1
  1491.             printf("..data available on socket %d\n",back[i].r.soc);
  1492. #endif
  1493.  
  1494.             
  1495.             // range size hack old location
  1496.  
  1497. #if HTS_DIRECTDISK
  1498.             // Court-circuit:
  1499.             // Peut-on stocker le fichier directement sur disque?
  1500.             // Ahh que ca serait vachement mieux et que ahh que la mΘmoire vous dit merci!
  1501.             if (back[i].status) {
  1502.               if (back[i].r.is_write==0) {  // mode mΘmoire
  1503.                 if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1504.                   if (!back[i].testmode) {  // pas mode test
  1505.                     if (strnotempty(back[i].url_sav)) {
  1506.                       if (strcmp(back[i].url_fil,"/robots.txt")) {
  1507.                         if (back[i].r.statuscode==200) {  // 'OK'
  1508.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1509.                             if (opt->getmode&2) {    // on peut ecrire des non html
  1510.                               back[i].r.is_write=1;    // Θcrire
  1511.                               if (back[i].r.compressed
  1512.                                 &&
  1513.                                 /* .gz are *NOT* depacked!! */
  1514.                                 (strfield(get_ext(back[i].url_sav),"gz") == 0)
  1515.                                 ) {
  1516.                                 back[i].tmpfile[0]='\0';
  1517.                                 strcpy(back[i].tmpfile,tempnam(NULL,"httrZ"));
  1518.                                 if (back[i].tmpfile[0])
  1519.                                   back[i].r.out=fopen(back[i].tmpfile,"wb");
  1520.                               } else {
  1521.                                 back[i].r.compressed=0;
  1522.                                 back[i].r.out=filecreate(back[i].url_sav);
  1523.                               }
  1524. #if HDEBUG
  1525.                               printf("direct-disk: %s\n",back[i].url_sav);
  1526. #endif
  1527.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1528.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File received from net to disk: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1529.                               }
  1530.                               
  1531.                               if (back[i].r.out==NULL) {
  1532.                                 if (opt->errlog) {
  1533.                                   fspc(opt->errlog,"error");
  1534.                                   fprintf(opt->errlog,"Unable to save file %s"LF,back[i].url_sav);
  1535.                                   test_flush;
  1536.                                 }
  1537.                                 back[i].r.is_write=0;    // erreur, abandonner
  1538. #if HDEBUG
  1539.                                 printf("..error!\n");
  1540. #endif
  1541.                               }
  1542. #if HTS_WIN==0
  1543.                               else chmod(back[i].url_sav,HTS_ACCESS_FILE);      
  1544. #endif          
  1545.                             } else {  // on coupe tout!
  1546.                               if ((opt->debug>1) && (opt->log!=NULL)) {
  1547.                                 fspc(opt->log,"debug"); fprintf(opt->log,"File cancelled (non HTML): %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1548.                               }
  1549.                               back[i].status=0;  // terminΘ
  1550.                               if (!back[i].testmode)
  1551.                                 back[i].r.statuscode=-10;    // EUHH CANCEL
  1552.                               else
  1553.                                 back[i].r.statuscode=-10;    // "TEST OK"
  1554.                               if (back[i].r.soc!=INVALID_SOCKET) {
  1555. #if HTS_DEBUG_CLOSESOCK
  1556.                                 DEBUG_W("back_wait(3): deletehttp\n");
  1557. #endif
  1558.                                 deletehttp(&back[i].r);
  1559.                               }
  1560.                               back[i].r.soc=INVALID_SOCKET;
  1561.                             }
  1562.                           }
  1563.                         }
  1564.                       }
  1565.                     }
  1566.                   }
  1567.                 }
  1568.               }
  1569.             }
  1570. #endif              
  1571.  
  1572.             // rΘception de donnΘes depuis socket ou fichier
  1573.             if (back[i].status) {
  1574.               if (back[i].status==99)  // recevoir par bloc de lignes
  1575.                 retour_fread=http_xfread1(&(back[i].r),0);
  1576.               else if (back[i].status==98) { // recevoir longueur chunk en hexa caractΦre par caractΦre
  1577.                 // backuper pour lire dans le buffer chunk
  1578.                 htsblk r;
  1579.                 memcpy(&r, &(back[i].r), sizeof(htsblk));
  1580.                 back[i].r.is_write=0;                   // mΘmoire
  1581.                 back[i].r.adr=back[i].chunk_adr;        // adresse
  1582.                 back[i].r.size=back[i].chunk_size;      // taille taille chunk
  1583.                 back[i].r.totalsize=-1;                 // total inconnu
  1584.                 back[i].r.out=NULL;
  1585.                 back[i].r.is_file=0;
  1586.                 //
  1587.                 // ligne par ligne
  1588.                 retour_fread=http_xfread1(&(back[i].r),-1);
  1589.                 // modifier et restaurer
  1590.                 back[i].chunk_adr=back[i].r.adr;        // adresse
  1591.                 back[i].chunk_size=back[i].r.size;      // taille taille chunk
  1592.                 memcpy(&(back[i].r), &r, sizeof(htsblk));    // restaurer vΘritable r
  1593.               }
  1594.               else if (back[i].is_chunk) {         // attention chunk, limiter taille α lire
  1595. #if CHUNKDEBUG==1
  1596.                 printf("read %d bytes\n",(int)min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1597. #endif
  1598.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) min(back[i].r.totalsize-back[i].r.size,max_read_bytes));
  1599.               } else              
  1600.                 retour_fread=(int) http_xfread1(&(back[i].r),(int) max_read_bytes);
  1601.                 // retour_fread=http_fread1(&(back[i].r));
  1602.             } else
  1603.               retour_fread=-1;                    // interruption ou annulation interne (peut ne pas Ωtre une erreur)
  1604.             
  1605.             // Si rΘception chunk, tester si on est pas α la fin!
  1606.             if (back[i].status==1) {
  1607.               if (back[i].is_chunk) {     // attendre prochain chunk
  1608.                 if (back[i].r.size==back[i].r.totalsize) {      // fin chunk!
  1609.                   //printf("chunk end at %d\n",back[i].r.size);
  1610.                   back[i].status=98;  // prochain chunk
  1611.                   if (back[i].chunk_adr!=NULL) { freet(back[i].chunk_adr); back[i].chunk_adr=NULL; } back[i].chunk_size=0;
  1612.                   retour_fread=0;       // pas d'erreur
  1613. #if CHUNKDEBUG==1
  1614.                   printf("waiting for next chunk header (soc %d)..\n",back[i].r.soc);
  1615. #endif
  1616.                 }
  1617.               }
  1618.             }
  1619.                           
  1620.             if (retour_fread < 0) {    // erreur rΘception
  1621.               back[i].status=0;    // terminΘ
  1622.               if (back[i].r.soc!=INVALID_SOCKET) {
  1623. #if HTS_DEBUG_CLOSESOCK
  1624.                 DEBUG_W("back_wait(4): deletehttp\n");
  1625. #endif
  1626.                 deletehttp(&back[i].r);
  1627.               }
  1628.               back[i].r.soc=INVALID_SOCKET;
  1629. #if CHUNKDEBUG==1
  1630.               if (back[i].is_chunk)
  1631.                 printf("must be the last chunk for %s (connection closed) - %d/%d\n",back[i].url_fil,back[i].r.size,back[i].r.totalsize);
  1632. #endif
  1633.               //if ((back[i].r.statuscode==-1) && (strnotempty(back[i].r.msg)==0)) {
  1634.               if ((back[i].r.statuscode<0) && (strnotempty(back[i].r.msg)==0)) {
  1635. #if HDEBUG
  1636.                 printf("error interruped: %s\n",back[i].r.adr);
  1637. #endif        
  1638.                 if (back[i].r.size>0)
  1639.                   strcat(back[i].r.msg,"Interrupted transfer");
  1640.                 else
  1641.                   strcat(back[i].r.msg,"No data (connection closed)");
  1642.                 back[i].r.statuscode=-4;
  1643.               }
  1644.  
  1645.               // finalize transfer
  1646.               if (back[i].r.statuscode>0) {
  1647.                 back_finalize(opt,cache,back,i);
  1648.               }
  1649.  
  1650.               if (back[i].r.totalsize>0) {    // tester totalsize
  1651.               //if ((back[i].r.totalsize>0) && (back[i].status==99)) {    // tester totalsize
  1652.                 if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1653.                   if (!opt->tolerant) {
  1654.                     //#if HTS_CL_IS_FATAL
  1655.                     if (back[i].r.adr) freet(back[i].r.adr); back[i].r.adr=NULL;
  1656.                     if (back[i].r.size<back[i].r.totalsize)
  1657.                       back[i].r.statuscode=-4;        // recatch
  1658.                     sprintf(back[i].r.msg,"Incorrect length ("LLintP" Bytes, "LLintP" expected)",back[i].r.size,back[i].r.totalsize);
  1659.                   } else {
  1660.                     //#else
  1661.                     // Un warning suffira..
  1662.                     if (cache->errlog!=NULL) {
  1663.                       fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,back[i].r.size,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1664.                     }
  1665.                     //#endif
  1666.                   }
  1667.                 }
  1668.               }
  1669. #if BDEBUG==1
  1670.               printf("transfer ok\n");
  1671. #endif
  1672.             } else if (retour_fread > 0) {    // pas d'erreur de rΘception et data
  1673.               if (back[i].timeout>0) {    // refresh timeout si besoin est
  1674.                 back[i].timeout_refresh=time_local();
  1675.               }
  1676.  
  1677.               // Traitement des en tΩtes chunks ou en tΩtes
  1678.               if (back[i].status==98) {        // rΘception taille chunk en hexa (  aprΦs les en tΩtes, peut ne pas
  1679.                 if (back[i].chunk_size>=2) {
  1680.                   int chunk_size=-1;
  1681.                   // Ωtre prΘsent)
  1682.                   if (back[i].chunk_adr[back[i].chunk_size-1]==10) {    // LF, fin ligne chunk
  1683.                     char chunk_data[64];
  1684.                     if (back[i].chunk_size<32) {      // pas trop gros
  1685.                       back[i].chunk_adr[ back[i].chunk_size-1]='\0';    // octet nul 
  1686.                       strcpy(chunk_data,"");    // hex number
  1687.                       strcat(chunk_data,back[i].chunk_adr);
  1688. #if CHUNKDEBUG==1
  1689.                       printf("chunk received and read: %s\n",chunk_data);
  1690. #endif
  1691.                       if (back[i].r.totalsize<0)
  1692.                         back[i].r.totalsize=0;        // initialiser α 0
  1693.                       if (sscanf(chunk_data,"%x",&chunk_size) == 1) {
  1694.                         back[i].r.totalsize+=chunk_size;    // noter taille
  1695.                         back[i].r.adr=(char*) realloct(back[i].r.adr,(INTsys) back[i].r.totalsize + 1);
  1696.                         if (!back[i].r.adr) {
  1697.                           if (cache->errlog!=NULL) {
  1698.                             fprintf(cache->errlog,"Error: Not enough memory ("LLintP") for %s%s"LF,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1699.                           }
  1700.                         }
  1701. #if CHUNKDEBUG==1
  1702.                         printf("chunk length: %d - next total "LLintP":\n",chunk_size,back[i].r.totalsize);
  1703. #endif
  1704.                       } else                                
  1705.                         if (cache->errlog!=NULL) {
  1706.                           fprintf(cache->errlog,"Warning: Illegal chunk (%s) for %s%s"LF,back[i].chunk_adr,back[i].url_adr,back[i].url_fil);
  1707.                         }
  1708.                     } else {                                  
  1709.                       if (cache->errlog!=NULL) {
  1710.                         fprintf(cache->errlog,"Warning: Chunk too big ("LLintP") for %s%s"LF,back[i].chunk_size,back[i].url_adr,back[i].url_fil);
  1711.                       }
  1712.                     }
  1713.                     
  1714.                     // ok, continuer sur le body
  1715.                     
  1716.                     // si chunk non nul continuer (ou commencer)
  1717.                     if (chunk_size>0) {
  1718.                       back[i].status=1;     // continuer body    
  1719. #if CHUNKDEBUG==1
  1720.                       printf("waiting for body (chunk)\n");
  1721. #endif
  1722.                     } else {                // chunk nul, c'est la fin
  1723. #if CHUNKDEBUG==1
  1724.                       printf("chunk end, total: %d\n",back[i].r.size);
  1725. #endif
  1726.                       back[i].status=0;     // fin  
  1727.                       // finalize transfer
  1728.                       back_finalize(opt,cache,back,i);
  1729.                       if (back[i].r.soc!=INVALID_SOCKET) {
  1730. #if HTS_DEBUG_CLOSESOCK
  1731.                         DEBUG_W("back_wait(5): deletehttp\n");
  1732. #endif
  1733.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1734.  
  1735.                         /* Tester totalsize en fin de chunk */
  1736.                         if ((back[i].r.totalsize>0)) {    // tester totalsize
  1737.                           if (back[i].r.totalsize!=back[i].r.size) {  // pas la mΩme!
  1738. #if HTS_CL_IS_FATAL
  1739.                             if (back[i].r.adr) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1740.                             back[i].r.statuscode=-1;
  1741.                             strcpy(back[i].r.msg,"Incorrect length");
  1742. #else
  1743.                             // Un warning suffira..
  1744.                             if (cache->errlog!=NULL) {
  1745.                               fspc(cache->errlog,"warning"); fprintf(cache->errlog,"Incorrect length ("LLintP"!="LLintP" expected) for %s%s"LF,back[i].r.size,back[i].r.totalsize,back[i].url_adr,back[i].url_fil);
  1746.                             }
  1747. #endif
  1748.                           }
  1749.                         }
  1750.                         
  1751.                       
  1752.                       }
  1753.                     }
  1754.  
  1755.                     // effacer buffer (chunk en tete)
  1756.                     if (back[i].chunk_adr!=NULL) {
  1757.                       freet(back[i].chunk_adr);
  1758.                       back[i].chunk_adr=NULL;
  1759.                       back[i].chunk_size=0;
  1760.                     }
  1761.                   
  1762.                   } // chunk LF?
  1763.                 }  // taille buffer chunk>2
  1764.                 //
  1765.               } else if (back[i].status==99) {        // en tΩtes (avant le chunk si il est prΘsent)
  1766.                 //
  1767.                 if (back[i].r.size>=2) {
  1768.                   // double LF
  1769.                   if ((back[i].r.adr[back[i].r.size-1]==10) && (back[i].r.adr[back[i].r.size-2]==10)) {
  1770.                     char rcvd[2048];
  1771.                     int ptr=0;
  1772.                     
  1773. #if BDEBUG==1
  1774.                     printf("..ok, header received\n");
  1775. #endif
  1776.  
  1777.                     // ----------------------------------------
  1778.                     // traiter en-tΩte!
  1779.                     // status-line α rΘcupΘrer
  1780.                     ptr+=binput(back[i].r.adr+ptr,rcvd,2000);
  1781.                     if (strnotempty(rcvd)==0)
  1782.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);    // "certains serveurs buggΘs envoient un \n au dΘbut" (RFC)
  1783.                     
  1784.                     // traiter status-line
  1785.                     treatfirstline(&back[i].r,rcvd);
  1786.                     
  1787. #if HDEBUG
  1788.                     printf("(Buffer) Status-Code=%d\n",back[i].r.statuscode);
  1789. #endif
  1790.                     if (_DEBUG_HEAD) {
  1791.                       if (ioinfo) {
  1792.                         fprintf(ioinfo,"response for %s%s:\r\ncode=%d\r\n",jump_identification(back[i].url_adr),back[i].url_fil,back[i].r.statuscode);
  1793.                         fprintfio(ioinfo,back[i].r.adr,">>> ");
  1794.                         fprintf(ioinfo,"\r\n");
  1795.                         fflush(ioinfo);
  1796.                       }                    // en-tΩte
  1797.                     }
  1798.                       
  1799.                     // header // ** !attention! HTTP/0.9 non supportΘ
  1800.                     do {
  1801.                       ptr+=binput(back[i].r.adr+ptr,rcvd,2000);          
  1802. #if HDEBUG
  1803.                       printf("(buffer)>%s\n",rcvd);      
  1804. #endif
  1805.                       /*
  1806.                       if (_DEBUG_HEAD) {
  1807.                         if (ioinfo) {
  1808.                           fprintf(ioinfo,"(buffer)>%s\r\n",rcvd);      
  1809.                           fflush(ioinfo);
  1810.                         }
  1811.                       }
  1812.                       */
  1813.  
  1814.                       if (strnotempty(rcvd))
  1815.                         treathead(opt->cookie,back[i].url_adr,back[i].url_fil,&back[i].r,rcvd);  // traiter
  1816.                       
  1817.                       // parfois les serveurs buggΘs renvoient un content-range avec un 200
  1818.                       if (back[i].r.statuscode==200)  // 'OK'
  1819.                         if (strfield(rcvd,"content-range:"))  // Avec un content-range: relisez les RFC..
  1820.                           back[i].r.statuscode=206;    // FORCER A 206 !!!!!
  1821.                         
  1822.                     } while(strnotempty(rcvd));
  1823.                     // ----------------------------------------                    
  1824.                     
  1825.                     // libΘrer mΘmoire  -- aprΦs! --
  1826.                     if (back[i].r.adr!=NULL) { freet(back[i].r.adr); back[i].r.adr=NULL; }
  1827.  
  1828.                     
  1829.  
  1830.  
  1831.                     /* 
  1832.                        Status code and header-response hacks
  1833.                     */
  1834.                     
  1835.                     // Check response : 203 == 200
  1836.                     if (back[i].r.statuscode==203) {  // 'Non-Authoritative Information'
  1837.                       back[i].r.statuscode=200;       // forcer "OK"
  1838.                     } else if (back[i].r.statuscode == 100) {
  1839.                       back[i].status=99;
  1840.                       back[i].r.size=0;
  1841.                       back[i].r.totalsize=0;
  1842.                       back[i].chunk_size=0;
  1843.                       back[i].r.statuscode=-1;
  1844.                       back[i].r.msg[0]='\0';
  1845.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  1846.                         fspc(opt->log,"debug"); fprintf(opt->log,"Status 100 detected for %s%s, continuing headers"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1847.                       }
  1848.                       continue;
  1849.                     }
  1850.                     
  1851.                     /*
  1852.                     Solve "false" 416 problems
  1853.                     */
  1854.                     if (back[i].r.statuscode==416) {  // 'Requested Range Not Satisfiable'
  1855.                       // Example:
  1856.                       // Range: bytes=2830-
  1857.                       // ->
  1858.                       // Content-Range: bytes */2830
  1859.                       if (back[i].range_req_size == back[i].r.crange) {
  1860.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1861.                         back[i].status=0;    // READY
  1862.                         back[i].r.size=back[i].r.totalsize=back[i].range_req_size;
  1863.                         filenote(back[i].url_sav,NULL);
  1864.                         back[i].r.statuscode=304;     // NOT MODIFIED
  1865.                         if ((opt->debug>1) && (opt->log!=NULL)) {
  1866.                           fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (good 416 message), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1867.                         }
  1868.                       }
  1869.                     }
  1870.                     
  1871.                     // Various hacks to limit re-transfers when updating a mirror
  1872.                     if (opt->sizehack) {
  1873.                       // We already have the file
  1874.                       // and ask the remote server for an update
  1875.                       // Some servers, especially dynamic pages severs, always
  1876.                       // answer that the page has been modified since last visit
  1877.                       // And answer with a 200 (OK) response, and the same page
  1878.                       // If the size is the same, and the option has been set, we assume
  1879.                       // that the file is identical - and therefore let's break the connection
  1880.                       if (back[i].is_update) {          // mise α jour
  1881.                         if (back[i].r.statuscode==200) {  // 'OK'
  1882.                           htsblk r = cache_read(opt,cache,back[i].url_adr,back[i].url_fil,NULL);    // lire entrΘe cache
  1883.                           if (r.statuscode == 200) {  // OK pas d'erreur cache
  1884.                             LLint len1,len2;
  1885.                             len1=r.totalsize;
  1886.                             len2=back[i].r.totalsize;
  1887.                             if (r.size>0)
  1888.                               len1=r.size;
  1889.                             if (len1>0) {
  1890.                               if (len1 == len2) {             // tailles identiques
  1891.                                 back[i].r.statuscode=304;     // forcer NOT MODIFIED
  1892.                                 deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1893.                                 if ((opt->debug>1) && (opt->log!=NULL)) {
  1894.                                   fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (same size), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1895.                                 }
  1896.                               }
  1897.                             }
  1898.                           } else {
  1899.                             if (opt->errlog!=NULL) {
  1900.                               fspc(opt->errlog,"warning"); fprintf(opt->errlog,"File seems complete (same size), but there was a cache read error: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1901.                             }
  1902.                           }
  1903.                         }
  1904.                       }
  1905.                     }
  1906.  
  1907.                     // Various hacks to limit re-transfers when updating a mirror
  1908.                     if (opt->sizehack) {
  1909.                       // We have request for a partial file (with a 'Range: NNN-' header)
  1910.                       // and received a complete file notification (200), with 'Content-length: NNN'
  1911.                       // it might be possible that we had the complete file
  1912.                       // this is the case in *most* cases, so break the connection
  1913.                       if (back[i].r.is_write==0) {  // mode mΘmoire
  1914.                         if (back[i].r.adr==NULL) {  // rien n'a ΘtΘ Θcrit
  1915.                           if (!back[i].testmode) {  // pas mode test
  1916.                             if (strnotempty(back[i].url_sav)) {
  1917.                               if (strcmp(back[i].url_fil,"/robots.txt")) {
  1918.                                 if (back[i].r.statuscode==200) {  // 'OK'
  1919.                                   if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  1920.                                     if (back[i].r.statuscode==200) {      // "OK"
  1921.                                       if (back[i].range_req_size>0) {     // but Range: requested
  1922.                                         if (back[i].range_req_size == back[i].r.totalsize) {    // And same size
  1923. #if HTS_DEBUG_CLOSESOCK
  1924.                                           DEBUG_W("back_wait(skip_range): deletehttp\n");
  1925. #endif
  1926.                                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1927.                                           back[i].status=0;    // READY
  1928.                                           back[i].r.size=back[i].r.totalsize;
  1929.                                           filenote(back[i].url_sav,NULL);
  1930.                                           back[i].r.statuscode=304;     // NOT MODIFIED
  1931.                                           if ((opt->debug>1) && (opt->log!=NULL)) {
  1932.                                             fspc(opt->log,"debug"); fprintf(opt->log,"File seems complete (reget failed), breaking connection: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1933.                                           }
  1934.                                         }
  1935.                                       }
  1936.                                     }
  1937.                                     
  1938.                                   }
  1939.                                 }
  1940.                               }
  1941.                             }
  1942.                           }
  1943.                         }
  1944.                       }
  1945.                     }
  1946.                     // END - Various hacks to limit re-transfers when updating a mirror
  1947.  
  1948.                     /* 
  1949.                     End of status code and header-response hacks
  1950.                     */
  1951.  
  1952.                     
  1953.                     
  1954.                     /* Interdiction taille par le wizard? */
  1955.                     if (back[i].r.soc!=INVALID_SOCKET) {
  1956.                       if (!back_checksize(opt,&back[i],1)) {
  1957.                         back[i].status=0;  // FINI
  1958.                         deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1959.                         if (!back[i].testmode)
  1960.                           strcpy(back[i].r.msg,"File too big");
  1961.                         else
  1962.                           strcpy(back[i].r.msg,"Test: File too big");
  1963.                       }
  1964.                     }
  1965.                     
  1966.                     /* sinon, continuer */
  1967.                     /* if (back[i].r.soc!=INVALID_SOCKET) {   // ok rΘcupΘrer body? */
  1968.                     // head: terminΘ
  1969.                     if (back[i].head_request) {
  1970.                       if ((opt->debug>1) && (opt->log!=NULL)) {
  1971.                         fspc(opt->log,"debug"); fprintf(opt->log,"Tested file: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  1972.                       }
  1973. #if HTS_DEBUG_CLOSESOCK
  1974.                       DEBUG_W("back_wait(head request): deletehttp\n");
  1975. #endif
  1976.                       // Couper connexion
  1977.                       deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1978.                       back[i].status=0;  // terminΘ
  1979.                     }
  1980.                     // traiter une Θventuelle erreur 304 (cache α jour utilisable)
  1981.                     else if (back[i].r.statuscode==304) {  // document α jour dans le cache
  1982.                       // lire dans le cache
  1983.                       // ** NOTE: pas de vΘrif de la taille ici!!
  1984. #if HTS_DEBUG_CLOSESOCK
  1985.                       DEBUG_W("back_wait(file is not modified): deletehttp\n");
  1986. #endif
  1987.                       deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  1988.                       back[i].r=cache_read(opt,cache,back[i].url_adr,back[i].url_fil,back[i].url_sav);
  1989.                       if (!back[i].r.location)
  1990.                         back[i].r.location=back[i].location_buffer;
  1991.                       else {        /* recopier */
  1992.                         strcpy(back[i].location_buffer,back[i].r.location);
  1993.                         back[i].r.location=back[i].location_buffer;
  1994.                       }
  1995.  
  1996.                       // hack:
  1997.                       // In case of 'if-unmodified-since' hack, a 304 status can be sent
  1998.                       // then, force 'ok' status
  1999.                       if (back[i].r.statuscode == -1) {
  2000.                         if (fexist(back[i].url_sav)) {
  2001.                           back[i].r.statuscode=200;     // OK
  2002.                           if ((opt->debug>0) && (opt->log!=NULL)) {
  2003.                             fspc(opt->log,"debug"); fprintf(opt->log,"Not-modified status without cache guessed: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2004.                           }
  2005.                         }
  2006.                       }
  2007.  
  2008.                       // Status is okay?
  2009.                       if (back[i].r.statuscode!=-1) { // pas d'erreur de lecture
  2010.                         back[i].status=0;         // OK prΩt
  2011.                         back[i].r.notmodified=1;  // NON modifiΘ!
  2012.                         if ((opt->debug>0) && (opt->log!=NULL)) {
  2013.                           fspc(opt->log,"debug"); fprintf(opt->log,"File loaded after test from cache: %s%s"LF,back[i].url_adr,back[i].url_fil); test_flush;
  2014.                         }
  2015.  
  2016.                         // finalize
  2017.                         if (back[i].r.statuscode>0) {
  2018.                           back_finalize(opt,cache,back,i);
  2019.                         }
  2020.                         
  2021. #if DEBUGCA
  2022.                         printf("..document α jour aprΦs requΦte: %s%s\n",back[i].url_adr,back[i].url_fil);
  2023. #endif
  2024.                         
  2025.                         //printf(">%s status %d\n",back[p].r.contenttype,back[p].r.statuscode);
  2026.                       } else {  // erreur
  2027.                         back[i].status=0;  // terminΘ
  2028.                         //printf("erreur cache\n");
  2029.                         
  2030.                       } 
  2031.                       
  2032.                     } else if ((back[i].r.statuscode==301)
  2033.                       || (back[i].r.statuscode==302)
  2034.                       || (back[i].r.statuscode==303)
  2035.                       || (back[i].r.statuscode==307)
  2036.                       || (back[i].r.statuscode==412)
  2037.                       || (back[i].r.statuscode==416)
  2038.                       ) {   // Ne pas prendre le html, erreurs connues et gΘrΘes
  2039. #if HTS_DEBUG_CLOSESOCK
  2040.                       DEBUG_W("back_wait(301,302,303,307,412,416..): deletehttp\n");
  2041. #endif
  2042.                       // Couper connexion
  2043.                       deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2044.                       back[i].status=0;  // terminΘ
  2045.                       // finalize
  2046.                       if (back[i].r.statuscode>0) {
  2047.                         back_finalize(opt,cache,back,i);
  2048.                       }
  2049.                     } else {    // il faut aller le chercher
  2050.                       
  2051.                       // effacer buffer (requΦte)
  2052.                       if (back[i].r.adr!=NULL) {
  2053.                         freet(back[i].r.adr);
  2054.                         back[i].r.adr=NULL;
  2055.                       }
  2056.                       back[i].r.size=0;                                 
  2057.                       
  2058.                       // traiter 206 (partial content)
  2059.                       // xxc SI CHUNK VERIFIER QUE CA MARCHE??
  2060.                       if (back[i].r.statuscode==206) {  // on nous envoie un morceau (la fin) coz une partie sur disque!
  2061.                         LLint sz=fsize(back[i].url_sav);
  2062. #if HDEBUG
  2063.                         printf("partial content: "LLintP" on disk..\n",(LLint)sz);
  2064. #endif
  2065.                         if (sz>=0) {
  2066.                           if (!is_hypertext_mime(back[i].r.contenttype)) {    // pas HTML
  2067.                             if (opt->getmode&2) {    // on peut ecrire des non html  **sinon ben euhh sera interceptΘ plus loin, donc rap sur ce qui va sortir**
  2068.                               filenote(back[i].url_sav,NULL);    // noter fichier comme connu
  2069.                               back[i].r.out=fopen(fconv(back[i].url_sav),"ab");  // append
  2070.                               if (back[i].r.out) {
  2071.                                 back[i].r.is_write=1;    // Θcrire
  2072.                                 back[i].r.size=sz;    // dΘja Θcrit
  2073.                                 back[i].r.statuscode=200;  // Forcer 'OK'
  2074.                                 if (back[i].r.totalsize>0)
  2075.                                   back[i].r.totalsize+=sz;    // plus en fait
  2076.                                 fseek(back[i].r.out,0,SEEK_END);  // α la fin
  2077. #if HDEBUG
  2078.                                 printf("continue interrupted file\n");
  2079. #endif
  2080.                               } else {    // On est dans la m**
  2081.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2082.                                 strcpy(back[i].r.msg,"Can not open partial file");
  2083.                               }
  2084.                             }
  2085.                           } else {    // mΘmoire
  2086.                             FILE* fp=fopen(fconv(back[i].url_sav),"rb");
  2087.                             if (fp) {
  2088.                               LLint alloc_mem=sz + 1;
  2089.                               if (back[i].r.totalsize>0)
  2090.                                 alloc_mem+=back[i].r.totalsize;            // AJOUTER RESTANT!
  2091.                               if ( (back[i].r.adr=(char*) malloct((INTsys) alloc_mem)) ) {
  2092.                                 back[i].r.size=sz;
  2093.                                 if (back[i].r.totalsize>0)
  2094.                                   back[i].r.totalsize+=sz;    // plus en fait
  2095.                                 if (((int) fread(back[i].r.adr,1,(INTsys)sz,fp)) != sz) {
  2096.                                   back[i].status=0;  // terminΘ (voir plus loin)
  2097.                                   strcpy(back[i].r.msg,"Can not read partial file");
  2098.                                 } else {
  2099.                                   back[i].r.statuscode=200;  // Forcer 'OK'
  2100. #if HDEBUG
  2101.                                   printf("continue in mem interrupted file\n");
  2102. #endif
  2103.                                 }
  2104.                               } else {
  2105.                                 back[i].status=0;  // terminΘ (voir plus loin)
  2106.                                 strcpy(back[i].r.msg,"No memory for partial file");
  2107.                               }
  2108.                               fclose(fp);
  2109.                             } else {  // Argh.. 
  2110.                               back[i].status=0;  // terminΘ (voir plus loin)
  2111.                               strcpy(back[i].r.msg,"Can not open partial file");
  2112.                             }
  2113.                           }
  2114.                         } else {    // Non trouvΘ??
  2115.                           back[i].status=0;  // terminΘ (voir plus loin)
  2116.                           strcpy(back[i].r.msg,"Can not find partial file");
  2117.                         }
  2118.                         // Erreur?
  2119.                         if (back[i].status==0) {
  2120.                           if (back[i].r.soc!=INVALID_SOCKET) {
  2121. #if HTS_DEBUG_CLOSESOCK
  2122.                             DEBUG_W("back_wait(206 solve problems): deletehttp\n");
  2123. #endif
  2124.                             deletehttp(&back[i].r);
  2125.                           }
  2126.                           back[i].r.soc=INVALID_SOCKET;
  2127.                           //back[i].r.statuscode=206;  ????????
  2128.                           back[i].r.statuscode=-5;
  2129.                           if (strnotempty(back[i].r.msg))
  2130.                             strcpy(back[i].r.msg,"Error attempting to solve status 206 (partial file)");
  2131.                         }
  2132.                       }
  2133.                       
  2134.                       if (back[i].status!=0) {  // non terminΘ (erreur)
  2135.                         if (!back[i].testmode) {    // fichier normal
  2136.                           
  2137.                           if (!back[i].r.is_chunk) {    // pas de chunk
  2138.                             //if (back[i].r.http11!=2) {    // pas de chunk
  2139.                             back[i].is_chunk=0;
  2140.                             back[i].status=1;     // start body
  2141.                           } else {
  2142. #if CHUNKDEBUG==1
  2143.                             printf("chunk encoding detected %s..\n",back[i].url_fil);
  2144. #endif
  2145.                             back[i].is_chunk=1;
  2146.                             back[i].chunk_adr=NULL;
  2147.                             back[i].chunk_size=0;
  2148.                             back[i].status=98;    // start body wait chunk
  2149.                           }
  2150.                           if (back[i].rateout>0) {
  2151.                             back[i].rateout_time=time_local();  // refresh pour transfer rate
  2152.                           }
  2153. #if HDEBUG
  2154.                           printf("(buffer) start body!\n");
  2155. #endif
  2156.                         } else {     // mode test, ne pas passer en 1!!
  2157.                           back[i].status=0;    // READY
  2158. #if HTS_DEBUG_CLOSESOCK
  2159.                           DEBUG_W("back_wait(test ok): deletehttp\n");
  2160. #endif
  2161.                           deletehttp(&back[i].r); back[i].r.soc=INVALID_SOCKET;
  2162.                           if (back[i].r.statuscode==200) {
  2163.                             strcpy(back[i].r.msg,"Test: OK");
  2164.                             back[i].r.statuscode=-10;    // test rΘussi
  2165.                           }
  2166.                           else {    // test a ΘchouΘ, on ne change rien sauf que l'erreur est α titre indicatif
  2167.                             char tempo[1000];
  2168.                             strcpy(tempo,back[i].r.msg);
  2169.                             strcpy(back[i].r.msg,"Test: ");
  2170.                             strcat(back[i].r.msg,tempo);
  2171.                           }
  2172.                           
  2173.                         }
  2174.                       }
  2175.                       
  2176.                       } 
  2177.                       
  2178.                       /*}*/
  2179.                       
  2180.                   }  // si LF
  2181.                 }  // r.size>2
  2182.               }  // si == 99
  2183.               
  2184.             } // si pas d'erreurs
  2185. #if BDEBUG==1
  2186.             printf("bytes overall: %d\n",back[i].r.size);
  2187. #endif
  2188.           }  // donnΘes dispo
  2189.           
  2190.           // en cas d'erreur cl, supprimer Θventuel fichier sur disque
  2191. #if HTS_REMOVE_BAD_FILES
  2192.           if (back[i].status<0) {
  2193.             if (!back[i].testmode) {    // pas en test
  2194.               remove(back[i].url_sav);    // Θliminer fichier (endommagΘ)
  2195.               //printf("&& %s\n",back[i].url_sav);
  2196.             }
  2197.           }
  2198. #endif
  2199.  
  2200.           /* funny log for commandline users */
  2201.           //if (!opt->quiet) {  
  2202.           // petite animation
  2203.           if (opt->verbosedisplay==1) {
  2204.             if (back[i].status==0) {
  2205.               if (back[i].r.statuscode==200)
  2206.                 printf("* %s%s ("LLintP" bytes) - OK"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,back[i].r.size);
  2207.               else
  2208.                 printf("* %s%s ("LLintP" bytes) - %d"VT_CLREOL"\r",back[i].url_adr,back[i].url_fil,back[i].r.size,back[i].r.statuscode);
  2209.               fflush(stdout);
  2210.             }
  2211.           }
  2212.           //}
  2213.           
  2214.  
  2215.       } // status>0
  2216.     }  // for
  2217.     
  2218.     // vΘrifier timeouts
  2219.     if (gestion_timeout) {
  2220.       TStamp act;
  2221.       act=time_local();    // temps en secondes
  2222.       for(i=0;i<back_max;i++) {
  2223.         if (back[i].status>0) {  // rΘception/connexion/..
  2224.           if (back[i].timeout>0) {
  2225.             //printf("time check %d\n",((int) (act-back[i].timeout_refresh))-back[i].timeout);
  2226.             if (((int) (act-back[i].timeout_refresh))>=back[i].timeout) {
  2227.               if (back[i].r.soc!=INVALID_SOCKET) {
  2228. #if HTS_DEBUG_CLOSESOCK
  2229.                 DEBUG_W("back_wait(timeout): deletehttp\n");
  2230. #endif
  2231.                 deletehttp(&back[i].r);
  2232.               }
  2233.               back[i].r.soc=INVALID_SOCKET;
  2234.               back[i].r.statuscode=-2;
  2235.               if (back[i].status==100)
  2236.                 strcpy(back[i].r.msg,"Connect Time Out");
  2237.               else if (back[i].status==101)
  2238.                 strcpy(back[i].r.msg,"DNS Time Out");
  2239.               else
  2240.                 strcpy(back[i].r.msg,"Receive Time Out");
  2241.               back[i].status=0;  // terminΘ
  2242.             } else if ((back[i].rateout>0) && (back[i].status<99)) {
  2243.               if (((int) (act-back[i].rateout_time))>=HTS_WATCHRATE) {   // checker au bout de 15s
  2244.                 if ( (int) ((back[i].r.size)/(act-back[i].rateout_time)) < back[i].rateout ) {  // trop lent
  2245.                   back[i].status=0;  // terminΘ
  2246.                   if (back[i].r.soc!=INVALID_SOCKET) {
  2247. #if HTS_DEBUG_CLOSESOCK
  2248.                     DEBUG_W("back_wait(rateout): deletehttp\n");
  2249. #endif
  2250.                     deletehttp(&back[i].r);
  2251.                   }
  2252.                   back[i].r.soc=INVALID_SOCKET;
  2253.                   back[i].r.statuscode=-3;
  2254.                   strcpy(back[i].r.msg,"Transfer Rate Too Low");
  2255.                 }
  2256.               }
  2257.             }
  2258.           }
  2259.         }
  2260.       }
  2261.     }
  2262.     max_loop--;
  2263. #if HTS_ANALYSTE
  2264.     max_loop_chk++;
  2265. #endif
  2266.   } while((busy_state) && (busy_recv) && (max_loop>0));
  2267. #if HTS_ANALYSTE
  2268.   if ((!busy_recv) && (!busy_state)) {
  2269.     if (max_loop_chk>=1) {
  2270.       Sleep(10);    // un tite pause pour Θviter les lag..
  2271.     }
  2272.   }
  2273. #endif
  2274. }
  2275.  
  2276. int back_checksize(httrackp* opt,lien_back* eback,int check_only_totalsize) {
  2277.   LLint size_to_test;
  2278.   if (check_only_totalsize)
  2279.     size_to_test=eback->r.totalsize;
  2280.   else
  2281.     size_to_test=max(eback->r.totalsize,eback->r.size);
  2282.   if (size_to_test>=0) {
  2283.     
  2284.     /* Interdiction taille par le wizard? */
  2285.     if (hts_testlinksize(opt,eback->url_adr,eback->url_fil,(eback->r.totalsize+1023)/1024)==-1) {
  2286.       return 0;     /* interdit */
  2287.     }                     
  2288.     
  2289.     /* vΘrifier taille classique (heml et non html) */
  2290.     if ((istoobig(size_to_test,eback->maxfile_html,eback->maxfile_nonhtml,eback->r.contenttype))) {
  2291.       return 0;     /* interdit */
  2292.     }
  2293.   }
  2294.   return 1;
  2295. }
  2296.  
  2297.  
  2298. // octets transfΘrΘs + add
  2299. LLint back_transfered(LLint nb,lien_back* back,int back_max) {
  2300.   int i;
  2301.   // ajouter octets en instance
  2302.   for(i=0;i<back_max;i++)
  2303.     if ((back[i].status>0) && (back[i].status<99))
  2304.       nb+=back[i].r.size;
  2305.   return nb;      
  2306. }
  2307.  
  2308. // infos backing
  2309. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2310. void back_info(lien_back* back,int i,int j,FILE* fp) {
  2311.   if (back[i].status>=0) {
  2312.     char s[256]; 
  2313.     s[0]='\0';
  2314.     back_infostr(back,i,j,s);
  2315.     strcat(s,LF);
  2316.     fprintf(fp,"%s",s);
  2317.   }
  2318. }
  2319.  
  2320. // infos backing
  2321. // j: 1 afficher sockets 2 afficher autres 3 tout afficher
  2322. void back_infostr(lien_back* back,int i,int j,char* s) {
  2323.   if (back[i].status>=0) {
  2324.     int aff=0;
  2325.     if (j & 1) {
  2326.       if (back[i].status==100) {
  2327.         strcat(s,"CONNECT ");
  2328.       } else if (back[i].status==99) {
  2329.         strcat(s,"INFOS ");
  2330.         aff=1;
  2331.       } else if (back[i].status==98) {
  2332.         strcat(s,"INFOSC");             // infos chunk
  2333.         aff=1;
  2334.       }
  2335.       else if (back[i].status>0) {
  2336. #if HTS_ANALYSTE==2
  2337.         strcat(s,"WAIT ");
  2338. #else
  2339.         strcat(s,"RECEIVE "); 
  2340. #endif
  2341.         aff=1; 
  2342.       }
  2343.     } 
  2344.     if (j & 2) {
  2345.       if (back[i].status==0) {
  2346.         switch (back[i].r.statuscode) {
  2347.         case 200:
  2348.           strcat(s,"READY ");
  2349.           aff=1;
  2350.           break;
  2351. #if HTS_ANALYSTE==2
  2352.         default:
  2353.           strcat(s,"ERROR ");
  2354.           break;
  2355. #else
  2356.         case -1:
  2357.           strcat(s,"ERROR ");
  2358.           aff=1;
  2359.           break;
  2360.         case -2:
  2361.           strcat(s,"TIMEOUT ");
  2362.           aff=1;
  2363.           break;
  2364.         case -3:
  2365.           strcat(s,"TOOSLOW ");
  2366.           aff=1;
  2367.           break;
  2368.         case 400:
  2369.           strcat(s,"BADREQUEST ");
  2370.           aff=1;
  2371.           break;
  2372.         case 401: case 403:
  2373.           strcat(s,"FORBIDDEN ");
  2374.           aff=1;
  2375.           break;
  2376.         case 404:
  2377.           strcat(s,"NOT FOUND ");
  2378.           aff=1;
  2379.           break;
  2380.         case 500:
  2381.           strcat(s,"SERVERROR ");
  2382.           aff=1;
  2383.           break;
  2384.         default:
  2385.           {
  2386.             char s2[256];
  2387.             sprintf(s2,"ERROR(%d)",back[i].r.statuscode);
  2388.             strcat(s,s2);
  2389.           }
  2390.           aff=1;
  2391. #endif
  2392.         }
  2393.       }
  2394.     }
  2395.     
  2396.     if (aff) {
  2397.       {
  2398.         char s2[1024];
  2399.         sprintf(s2,"\"%s",back[i].url_adr); strcat(s,s2);
  2400.         
  2401.         if (back[i].url_fil[0]!='/') strcat(s,"/");
  2402.         sprintf(s2,"%s\" ",back[i].url_fil); strcat(s,s2);
  2403.         sprintf(s,LLintP" "LLintP" ",back[i].r.size,back[i].r.totalsize); strcat(s,s2);
  2404.       }
  2405.     }
  2406.   }
  2407. }
  2408.  
  2409. // -- backing --
  2410.  
  2411. #undef test_flush
  2412.